Skip to content

Commit 570d838

Browse files
alexcarpenterwobsoriano
andauthoredFeb 11, 2025··
feat(clerk-react,astro,vue): Add appearance option to modal components (#5125)
Co-authored-by: Robert Soriano <sorianorobertc@gmail.com>
1 parent ab06832 commit 570d838

File tree

15 files changed

+163
-176
lines changed

15 files changed

+163
-176
lines changed
 

‎.changeset/few-news-impress.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@clerk/astro': patch
3+
'@clerk/clerk-react': patch
4+
'@clerk/vue': patch
5+
---
6+
7+
Add the ability to specify an appearance for modal component usages.

‎.changeset/giant-fans-pretend.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/types': minor
3+
---
4+
5+
Extract common button component props.

‎packages/astro/src/astro-components/unstyled/SignInButton.astro

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
---
22
import type { HTMLTag, Polymorphic } from 'astro/types'
3-
import type { SignInProps } from '@clerk/types'
3+
import type { SignInButtonProps } from '@clerk/types'
44
import type { ButtonProps } from '../../types';
55
import { addUnstyledAttributeToFirstTag, logAsPropUsageDeprecation } from './utils'
66
7-
type Props<Tag extends HTMLTag = 'button'> = Polymorphic<SignInProps & ButtonProps<Tag>>
7+
type Props<Tag extends HTMLTag = 'button'> = Polymorphic<ButtonProps<Tag>> & SignInButtonProps;
88
99
import { generateSafeId } from '@clerk/astro/internal';
1010
@@ -22,7 +22,7 @@ const {
2222
signUpFallbackRedirectUrl,
2323
signUpForceRedirectUrl,
2424
mode,
25-
...elementProps
25+
...props
2626
} = Astro.props
2727
2828
const signInOptions = {
@@ -44,20 +44,20 @@ if (asChild) {
4444
asChild ? (
4545
<Fragment set:html={htmlElement} />
4646
) : (
47-
<Tag {...elementProps} data-clerk-unstyled-id={safeId}>
47+
<Tag {...props} data-clerk-unstyled-id={safeId}>
4848
<slot>Sign in</slot>
4949
</Tag >
5050
)
5151
}
5252

53-
<script is:inline define:vars={{ signInOptions, mode, safeId }}>
53+
<script is:inline define:vars={{ props, signInOptions, mode, safeId }}>
5454
const btn = document.querySelector(`[data-clerk-unstyled-id="${safeId}"]`);
5555

5656
btn.addEventListener("click", () => {
5757
const clerk = window.Clerk
5858

5959
if (mode === 'modal') {
60-
return clerk.openSignIn(signInOptions);
60+
return clerk.openSignIn({ ...signInOptions, appearance: props.appearance });
6161
}
6262

6363
return clerk.redirectToSignIn({

‎packages/astro/src/astro-components/unstyled/SignOutButton.astro

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { SignOutOptions, Without } from '@clerk/types'
44
import type { ButtonProps } from '../../types';
55
import { addUnstyledAttributeToFirstTag, logAsPropUsageDeprecation } from './utils'
66
7-
type Props<Tag extends HTMLTag = 'button'> = Polymorphic<SignOutOptions & Without<ButtonProps<Tag>, 'mode'>>
7+
type Props<Tag extends HTMLTag = 'button'> = Polymorphic<SignOutOptions & ButtonProps<Tag>>
88
99
import { generateSafeId } from '@clerk/astro/internal'
1010

‎packages/astro/src/astro-components/unstyled/SignUpButton.astro

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
---
22
import type { HTMLTag, Polymorphic } from 'astro/types'
3-
import type { SignUpProps } from '@clerk/types'
3+
import type { SignUpButtonProps } from '@clerk/types'
44
import type { ButtonProps } from '../../types'
55
import { addUnstyledAttributeToFirstTag, logAsPropUsageDeprecation } from './utils'
66
7-
type Props<Tag extends HTMLTag = 'button'> = Polymorphic<SignUpProps & ButtonProps<Tag>>
7+
type Props<Tag extends HTMLTag = 'button'> = Polymorphic<ButtonProps<Tag>> & SignUpButtonProps;
88
99
import { generateSafeId } from '@clerk/astro/internal';
1010
@@ -23,7 +23,7 @@ const {
2323
signInForceRedirectUrl,
2424
mode,
2525
unsafeMetadata,
26-
...elementProps
26+
...props
2727
} = Astro.props
2828
2929
const signUpOptions = {
@@ -46,20 +46,20 @@ if (asChild) {
4646
asChild ? (
4747
<Fragment set:html={htmlElement} />
4848
) : (
49-
<Tag {...elementProps} data-clerk-unstyled-id={safeId}>
49+
<Tag {...props} data-clerk-unstyled-id={safeId}>
5050
<slot>Sign up</slot>
5151
</Tag >
5252
)
5353
}
5454

55-
<script is:inline define:vars={{ signUpOptions, mode, safeId }}>
55+
<script is:inline define:vars={{ props, signUpOptions, mode, safeId }}>
5656
const btn = document.querySelector(`[data-clerk-unstyled-id="${safeId}"]`);
5757

5858
btn.addEventListener("click", () => {
5959
const clerk = window.Clerk
6060

6161
if (mode === 'modal') {
62-
return clerk.openSignUp(signUpOptions);
62+
return clerk.openSignUp({ ...signUpOptions, appearance: props.appearance });
6363
}
6464

6565
return clerk.redirectToSignUp({
+40-38
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,48 @@
1-
import type { SignInProps } from '@clerk/types';
1+
import type { SignInButtonProps, SignInProps } from '@clerk/types';
22
import React from 'react';
33

4-
import type { SignInButtonProps } from './types';
54
import { assertSingleChild, normalizeWithDefaultValue, safeExecute, withClerk, type WithClerkProp } from './utils';
65

76
export type { SignInButtonProps };
87

9-
export const SignInButton = withClerk(({ clerk, children, ...props }: WithClerkProp<SignInButtonProps>) => {
10-
const { signUpFallbackRedirectUrl, forceRedirectUrl, fallbackRedirectUrl, signUpForceRedirectUrl, mode, ...rest } =
11-
props;
12-
children = normalizeWithDefaultValue(children, 'Sign in');
13-
const child = assertSingleChild(children)('SignInButton');
14-
15-
const clickHandler = () => {
16-
const opts: SignInProps = {
17-
forceRedirectUrl,
18-
fallbackRedirectUrl,
19-
signUpFallbackRedirectUrl,
20-
signUpForceRedirectUrl,
8+
export const SignInButton = withClerk(
9+
({ clerk, children, ...props }: WithClerkProp<React.PropsWithChildren<SignInButtonProps>>) => {
10+
const { signUpFallbackRedirectUrl, forceRedirectUrl, fallbackRedirectUrl, signUpForceRedirectUrl, mode, ...rest } =
11+
props;
12+
children = normalizeWithDefaultValue(children, 'Sign in');
13+
const child = assertSingleChild(children)('SignInButton');
14+
15+
const clickHandler = () => {
16+
const opts: SignInProps = {
17+
forceRedirectUrl,
18+
fallbackRedirectUrl,
19+
signUpFallbackRedirectUrl,
20+
signUpForceRedirectUrl,
21+
};
22+
23+
if (!clerk) {
24+
return;
25+
}
26+
27+
if (mode === 'modal') {
28+
return clerk.openSignIn({ ...opts, appearance: props.appearance });
29+
}
30+
return clerk.redirectToSignIn({
31+
...opts,
32+
signInFallbackRedirectUrl: fallbackRedirectUrl,
33+
signInForceRedirectUrl: forceRedirectUrl,
34+
});
2135
};
2236

23-
if (!clerk) {
24-
return;
25-
}
26-
27-
if (mode === 'modal') {
28-
return clerk.openSignIn(opts);
29-
}
30-
return clerk.redirectToSignIn({
31-
...opts,
32-
signInFallbackRedirectUrl: fallbackRedirectUrl,
33-
signInForceRedirectUrl: forceRedirectUrl,
34-
});
35-
};
36-
37-
const wrappedChildClickHandler: React.MouseEventHandler = async e => {
38-
if (child && typeof child === 'object' && 'props' in child) {
39-
await safeExecute(child.props.onClick)(e);
40-
}
41-
return clickHandler();
42-
};
43-
44-
const childProps = { ...rest, onClick: wrappedChildClickHandler };
45-
return React.cloneElement(child as React.ReactElement<unknown>, childProps);
46-
}, 'SignInButton');
37+
const wrappedChildClickHandler: React.MouseEventHandler = async e => {
38+
if (child && typeof child === 'object' && 'props' in child) {
39+
await safeExecute(child.props.onClick)(e);
40+
}
41+
return clickHandler();
42+
};
43+
44+
const childProps = { ...rest, onClick: wrappedChildClickHandler };
45+
return React.cloneElement(child as React.ReactElement<unknown>, childProps);
46+
},
47+
'SignInButton',
48+
);
+45-43
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,58 @@
1-
import type { SignUpProps } from '@clerk/types';
1+
import type { SignUpButtonProps, SignUpProps } from '@clerk/types';
22
import React from 'react';
33

4-
import type { SignUpButtonProps } from './types';
54
import { assertSingleChild, normalizeWithDefaultValue, safeExecute, withClerk, type WithClerkProp } from './utils';
65

76
export type { SignUpButtonProps };
87

9-
export const SignUpButton = withClerk(({ clerk, children, ...props }: WithClerkProp<SignUpButtonProps>) => {
10-
const {
11-
fallbackRedirectUrl,
12-
forceRedirectUrl,
13-
signInFallbackRedirectUrl,
14-
signInForceRedirectUrl,
15-
mode,
16-
unsafeMetadata,
17-
...rest
18-
} = props;
19-
20-
children = normalizeWithDefaultValue(children, 'Sign up');
21-
const child = assertSingleChild(children)('SignUpButton');
22-
23-
const clickHandler = () => {
24-
const opts: SignUpProps = {
8+
export const SignUpButton = withClerk(
9+
({ clerk, children, ...props }: WithClerkProp<React.PropsWithChildren<SignUpButtonProps>>) => {
10+
const {
2511
fallbackRedirectUrl,
2612
forceRedirectUrl,
2713
signInFallbackRedirectUrl,
2814
signInForceRedirectUrl,
15+
mode,
2916
unsafeMetadata,
17+
...rest
18+
} = props;
19+
20+
children = normalizeWithDefaultValue(children, 'Sign up');
21+
const child = assertSingleChild(children)('SignUpButton');
22+
23+
const clickHandler = () => {
24+
const opts: SignUpProps = {
25+
fallbackRedirectUrl,
26+
forceRedirectUrl,
27+
signInFallbackRedirectUrl,
28+
signInForceRedirectUrl,
29+
unsafeMetadata,
30+
};
31+
32+
if (!clerk) {
33+
return;
34+
}
35+
36+
if (mode === 'modal') {
37+
return clerk.openSignUp({ ...opts, appearance: props.appearance });
38+
}
39+
40+
return clerk.redirectToSignUp({
41+
...opts,
42+
signUpFallbackRedirectUrl: fallbackRedirectUrl,
43+
signUpForceRedirectUrl: forceRedirectUrl,
44+
});
3045
};
3146

32-
if (!clerk) {
33-
return;
34-
}
35-
36-
if (mode === 'modal') {
37-
return clerk.openSignUp(opts);
38-
}
39-
40-
return clerk.redirectToSignUp({
41-
...opts,
42-
signUpFallbackRedirectUrl: fallbackRedirectUrl,
43-
signUpForceRedirectUrl: forceRedirectUrl,
44-
});
45-
};
46-
47-
const wrappedChildClickHandler: React.MouseEventHandler = async e => {
48-
if (child && typeof child === 'object' && 'props' in child) {
49-
await safeExecute(child.props.onClick)(e);
50-
}
51-
return clickHandler();
52-
};
53-
54-
const childProps = { ...rest, onClick: wrappedChildClickHandler };
55-
return React.cloneElement(child as React.ReactElement<unknown>, childProps);
56-
}, 'SignUpButton');
47+
const wrappedChildClickHandler: React.MouseEventHandler = async e => {
48+
if (child && typeof child === 'object' && 'props' in child) {
49+
await safeExecute(child.props.onClick)(e);
50+
}
51+
return clickHandler();
52+
};
53+
54+
const childProps = { ...rest, onClick: wrappedChildClickHandler };
55+
return React.cloneElement(child as React.ReactElement<unknown>, childProps);
56+
},
57+
'SignUpButton',
58+
);

‎packages/astro/src/react/types.ts

+5-19
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,9 @@
1-
import type { SignInProps, SignUpProps } from '@clerk/types';
1+
import type { SignInButtonProps as _SignInButtonProps, SignUpButtonProps as _SignUpButtonProps } from '@clerk/types';
22

3-
// TODO-SHARED: Duplicate from @clerk/clerk-react
4-
type ButtonProps = {
5-
mode?: 'redirect' | 'modal';
3+
export type SignInButtonProps = _SignInButtonProps & {
64
children?: React.ReactNode;
75
};
86

9-
// TODO-SHARED: Duplicate from @clerk/clerk-react
10-
export type SignInButtonProps = ButtonProps &
11-
Pick<
12-
SignInProps,
13-
'fallbackRedirectUrl' | 'forceRedirectUrl' | 'signUpForceRedirectUrl' | 'signUpFallbackRedirectUrl'
14-
>;
15-
16-
// TODO-SHARED: Duplicate from @clerk/clerk-react
17-
export type SignUpButtonProps = {
18-
unsafeMetadata?: SignUpUnsafeMetadata;
19-
} & ButtonProps &
20-
Pick<
21-
SignUpProps,
22-
'fallbackRedirectUrl' | 'forceRedirectUrl' | 'signInForceRedirectUrl' | 'signInFallbackRedirectUrl'
23-
>;
7+
export type SignUpButtonProps = _SignUpButtonProps & {
8+
children?: React.ReactNode;
9+
};

‎packages/astro/src/types.ts

-1
Original file line numberDiff line numberDiff line change
@@ -82,5 +82,4 @@ export type ButtonProps<Tag> = {
8282
*/
8383
as: Tag;
8484
asChild?: boolean;
85-
mode?: 'redirect' | 'modal';
8685
};

‎packages/react/src/components/SignInButton.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import type { SignInProps } from '@clerk/types';
1+
import type { SignInButtonProps, SignInProps } from '@clerk/types';
22
import React from 'react';
33

4-
import type { SignInButtonProps, WithClerkProp } from '../types';
4+
import type { WithClerkProp } from '../types';
55
import { assertSingleChild, normalizeWithDefaultValue, safeExecute } from '../utils';
66
import { withClerk } from './withClerk';
77

88
export const SignInButton = withClerk(
9-
({ clerk, children, ...props }: WithClerkProp<SignInButtonProps>) => {
9+
({ clerk, children, ...props }: WithClerkProp<React.PropsWithChildren<SignInButtonProps>>) => {
1010
const {
1111
signUpFallbackRedirectUrl,
1212
forceRedirectUrl,
@@ -31,7 +31,7 @@ export const SignInButton = withClerk(
3131
};
3232

3333
if (mode === 'modal') {
34-
return clerk.openSignIn(opts);
34+
return clerk.openSignIn({ ...opts, appearance: props.appearance });
3535
}
3636
return clerk.redirectToSignIn({
3737
...opts,

‎packages/react/src/components/SignUpButton.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import type { SignUpProps } from '@clerk/types';
1+
import type { SignUpButtonProps, SignUpProps } from '@clerk/types';
22
import React from 'react';
33

4-
import type { SignUpButtonProps, WithClerkProp } from '../types';
4+
import type { WithClerkProp } from '../types';
55
import { assertSingleChild, normalizeWithDefaultValue, safeExecute } from '../utils';
66
import { withClerk } from './withClerk';
77

88
export const SignUpButton = withClerk(
9-
({ clerk, children, ...props }: WithClerkProp<SignUpButtonProps>) => {
9+
({ clerk, children, ...props }: WithClerkProp<React.PropsWithChildren<SignUpButtonProps>>) => {
1010
const {
1111
fallbackRedirectUrl,
1212
forceRedirectUrl,
@@ -32,7 +32,7 @@ export const SignUpButton = withClerk(
3232
};
3333

3434
if (mode === 'modal') {
35-
return clerk.openSignUp(opts);
35+
return clerk.openSignUp({ ...opts, appearance: props.appearance });
3636
}
3737

3838
return clerk.redirectToSignUp({

0 commit comments

Comments
 (0)
Please sign in to comment.