Skip to content

Commit 6ee96e8

Browse files
committed
feat(clerk-js,clerk-react,nextjs): Export TaskResetPassword component (#7314)
1 parent c20f7ab commit 6ee96e8

File tree

14 files changed

+124
-2
lines changed

14 files changed

+124
-2
lines changed

.changeset/modern-coins-camp.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@clerk/clerk-js": minor
3+
"@clerk/nextjs": minor
4+
"@clerk/clerk-react": minor
5+
"@clerk/shared": minor
6+
---
7+
8+
Introduce new `<TaskResetPassword/>` session task component

packages/clerk-js/sandbox/app.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const AVAILABLE_COMPONENTS = [
3737
'apiKeys',
3838
'oauthConsent',
3939
'taskChooseOrganization',
40+
'taskResetPassword',
4041
] as const;
4142

4243
const COMPONENT_PROPS_NAMESPACE = 'clerk-js-sandbox';
@@ -99,6 +100,7 @@ const componentControls: Record<(typeof AVAILABLE_COMPONENTS)[number], Component
99100
apiKeys: buildComponentControls('apiKeys'),
100101
oauthConsent: buildComponentControls('oauthConsent'),
101102
taskChooseOrganization: buildComponentControls('taskChooseOrganization'),
103+
taskResetPassword: buildComponentControls('taskResetPassword'),
102104
};
103105

104106
declare global {
@@ -352,6 +354,14 @@ void (async () => {
352354
},
353355
);
354356
},
357+
'/task-reset-password': () => {
358+
Clerk.mountTaskResetPassword(
359+
app,
360+
componentControls.taskResetPassword.getProps() ?? {
361+
redirectUrlComplete: '/user-profile',
362+
},
363+
);
364+
},
355365
'/open-sign-in': () => {
356366
mountOpenSignInButton(app, componentControls.signIn.getProps() ?? {});
357367
},

packages/clerk-js/src/core/clerk.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ import type {
108108
SignUpRedirectOptions,
109109
SignUpResource,
110110
TaskChooseOrganizationProps,
111+
TaskResetPasswordProps,
111112
TasksRedirectOptions,
112113
UnsubscribeCallback,
113114
UserAvatarProps,
@@ -1391,6 +1392,26 @@ export class Clerk implements ClerkInterface {
13911392
void this.#clerkUi?.then(ui => ui.ensureMounted()).then(controls => controls.unmountComponent({ node }));
13921393
};
13931394

1395+
public mountTaskResetPassword = (node: HTMLDivElement, props?: TaskResetPasswordProps) => {
1396+
this.assertComponentsReady(this.#componentControls);
1397+
1398+
void this.#componentControls.ensureMounted({ preloadHint: 'TaskResetPassword' }).then(controls =>
1399+
controls.mountComponent({
1400+
name: 'TaskResetPassword',
1401+
appearanceKey: 'taskResetPassword',
1402+
node,
1403+
props,
1404+
}),
1405+
);
1406+
1407+
this.telemetry?.record(eventPrebuiltComponentMounted('TaskResetPassword', props));
1408+
};
1409+
1410+
public unmountTaskResetPassword = (node: HTMLDivElement) => {
1411+
this.assertComponentsReady(this.#componentControls);
1412+
void this.#componentControls.ensureMounted().then(controls => controls.unmountComponent({ node }));
1413+
};
1414+
13941415
/**
13951416
* `setActive` can be used to set the active session and/or organization.
13961417
*/

packages/nextjs/src/client-boundary/uiComponents.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export {
2323
SignOutButton,
2424
SignUpButton,
2525
TaskChooseOrganization,
26+
TaskResetPassword,
2627
UserAvatar,
2728
UserButton,
2829
Waitlist,

packages/nextjs/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export {
3535
SignUp,
3636
SignUpButton,
3737
TaskChooseOrganization,
38+
TaskResetPassword,
3839
UserAvatar,
3940
UserButton,
4041
UserProfile,

packages/react-router/src/__tests__/__snapshots__/exports.test.ts.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ exports[`root public exports > should not change unexpectedly 1`] = `
4545
"SignedIn",
4646
"SignedOut",
4747
"TaskChooseOrganization",
48+
"TaskResetPassword",
4849
"UserAvatar",
4950
"UserButton",
5051
"UserProfile",

packages/react/src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export {
99
SignIn,
1010
SignUp,
1111
TaskChooseOrganization,
12+
TaskResetPassword,
1213
UserAvatar,
1314
UserButton,
1415
UserProfile,

packages/react/src/components/uiComponents.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type {
99
SignInProps,
1010
SignUpProps,
1111
TaskChooseOrganizationProps,
12+
TaskResetPasswordProps,
1213
UserAvatarProps,
1314
UserButtonProps,
1415
UserProfileProps,
@@ -696,3 +697,31 @@ export const TaskChooseOrganization = withClerk(
696697
},
697698
{ component: 'TaskChooseOrganization', renderWhileLoading: true },
698699
);
700+
701+
export const TaskResetPassword = withClerk(
702+
({ clerk, component, fallback, ...props }: WithClerkProp<TaskResetPasswordProps & FallbackProp>) => {
703+
const mountingStatus = useWaitForComponentMount(component);
704+
const shouldShowFallback = mountingStatus === 'rendering' || !clerk.loaded;
705+
706+
const rendererRootProps = {
707+
...(shouldShowFallback && fallback && { style: { display: 'none' } }),
708+
};
709+
710+
return (
711+
<>
712+
{shouldShowFallback && fallback}
713+
{clerk.loaded && (
714+
<ClerkHostRenderer
715+
component={component}
716+
mount={clerk.mountTaskResetPassword}
717+
unmount={clerk.unmountTaskResetPassword}
718+
updateProps={(clerk as any).__unstable__updateProps}
719+
props={props}
720+
rootProps={rendererRootProps}
721+
/>
722+
)}
723+
</>
724+
);
725+
},
726+
{ component: 'TaskResetPassword', renderWhileLoading: true },
727+
);

packages/react/src/isomorphicClerk.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import type {
4848
SignUpResource,
4949
State,
5050
TaskChooseOrganizationProps,
51+
TaskResetPasswordProps,
5152
TasksRedirectOptions,
5253
UnsubscribeCallback,
5354
UserAvatarProps,
@@ -152,7 +153,7 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk {
152153
private premountAPIKeysNodes = new Map<HTMLDivElement, APIKeysProps | undefined>();
153154
private premountOAuthConsentNodes = new Map<HTMLDivElement, __internal_OAuthConsentProps | undefined>();
154155
private premountTaskChooseOrganizationNodes = new Map<HTMLDivElement, TaskChooseOrganizationProps | undefined>();
155-
156+
private premountTaskResetPasswordNodes = new Map<HTMLDivElement, TaskResetPasswordProps | undefined>();
156157
// A separate Map of `addListener` method calls to handle multiple listeners.
157158
private premountAddListenerCalls = new Map<
158159
ListenerCallback,
@@ -689,6 +690,10 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk {
689690
clerkjs.mountTaskChooseOrganization(node, props);
690691
});
691692

693+
this.premountTaskResetPasswordNodes.forEach((props, node) => {
694+
clerkjs.mountTaskResetPassword(node, props);
695+
});
696+
692697
/**
693698
* Only update status in case `clerk.status` is missing. In any other case, `clerk-js` should be the orchestrator.
694699
*/
@@ -1233,6 +1238,22 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk {
12331238
}
12341239
};
12351240

1241+
mountTaskResetPassword = (node: HTMLDivElement, props?: TaskResetPasswordProps): void => {
1242+
if (this.clerkjs && this.loaded) {
1243+
this.clerkjs.mountTaskResetPassword(node, props);
1244+
} else {
1245+
this.premountTaskResetPasswordNodes.set(node, props);
1246+
}
1247+
};
1248+
1249+
unmountTaskResetPassword = (node: HTMLDivElement): void => {
1250+
if (this.clerkjs && this.loaded) {
1251+
this.clerkjs.unmountTaskResetPassword(node);
1252+
} else {
1253+
this.premountTaskResetPasswordNodes.delete(node);
1254+
}
1255+
};
1256+
12361257
addListener = (listener: ListenerCallback): UnsubscribeCallback => {
12371258
if (this.clerkjs) {
12381259
return this.clerkjs.addListener(listener);

packages/shared/src/types/clerk.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,22 @@ export interface Clerk {
656656
*/
657657
unmountTaskChooseOrganization: (targetNode: HTMLDivElement) => void;
658658

659+
/**
660+
* Mounts a TaskResetPassword component at the target element.
661+
*
662+
* @param targetNode - Target node to mount the TaskResetPassword component.
663+
* @param props - configuration parameters.
664+
*/
665+
mountTaskResetPassword: (targetNode: HTMLDivElement, props?: TaskResetPasswordProps) => void;
666+
667+
/**
668+
* Unmount a TaskResetPassword component from the target element.
669+
* If there is no component mounted at the target node, results in a noop.
670+
*
671+
* @param targetNode - Target node to unmount the TaskResetPassword component from.
672+
*/
673+
unmountTaskResetPassword: (targetNode: HTMLDivElement) => void;
674+
659675
/**
660676
* @internal
661677
* Loads Stripe libraries for commerce functionality

0 commit comments

Comments
 (0)