Skip to content

Commit

Permalink
let button components render while clerk is loading
Browse files Browse the repository at this point in the history
  • Loading branch information
BRKalow committed Dec 18, 2024
1 parent 4c605ee commit 4e5825a
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 75 deletions.
5 changes: 5 additions & 0 deletions .changeset/sixty-moose-jog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/clerk-react': minor
---

Allow `<SignInButton />`, <SignUpButton />`, `<SignOutButton />`, and `<SignInWithMetamaskButton />` to render while clerk-js is still loading. This reduces any layout shift that might be caused by these components not rendering immediately.
73 changes: 38 additions & 35 deletions packages/react/src/components/SignInButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,48 @@ import type { SignInButtonProps, WithClerkProp } from '../types';
import { assertSingleChild, normalizeWithDefaultValue, safeExecute } from '../utils';
import { withClerk } from './withClerk';

export const SignInButton = withClerk(({ clerk, children, ...props }: WithClerkProp<SignInButtonProps>) => {
const {
signUpFallbackRedirectUrl,
forceRedirectUrl,
fallbackRedirectUrl,
signUpForceRedirectUrl,
mode,
initialValues,
...rest
} = props;
children = normalizeWithDefaultValue(children, 'Sign in');
const child = assertSingleChild(children)('SignInButton');

const clickHandler = () => {
const opts: SignInProps = {
export const SignInButton = withClerk(
({ clerk, children, ...props }: WithClerkProp<SignInButtonProps>) => {
const {
signUpFallbackRedirectUrl,
forceRedirectUrl,
fallbackRedirectUrl,
signUpFallbackRedirectUrl,
signUpForceRedirectUrl,
mode,
initialValues,
};
...rest
} = props;
children = normalizeWithDefaultValue(children, 'Sign in');
const child = assertSingleChild(children)('SignInButton');

if (mode === 'modal') {
return clerk.openSignIn(opts);
}
return clerk.redirectToSignIn({
...opts,
signInFallbackRedirectUrl: fallbackRedirectUrl,
signInForceRedirectUrl: forceRedirectUrl,
});
};
const clickHandler = () => {
const opts: SignInProps = {
forceRedirectUrl,
fallbackRedirectUrl,
signUpFallbackRedirectUrl,
signUpForceRedirectUrl,
initialValues,
};

const wrappedChildClickHandler: React.MouseEventHandler = async e => {
if (child && typeof child === 'object' && 'props' in child) {
await safeExecute(child.props.onClick)(e);
}
return clickHandler();
};
if (mode === 'modal') {
return clerk.openSignIn(opts);
}
return clerk.redirectToSignIn({
...opts,
signInFallbackRedirectUrl: fallbackRedirectUrl,
signInForceRedirectUrl: forceRedirectUrl,
});
};

const wrappedChildClickHandler: React.MouseEventHandler = async e => {
if (child && typeof child === 'object' && 'props' in child) {
await safeExecute(child.props.onClick)(e);
}
return clickHandler();
};

const childProps = { ...rest, onClick: wrappedChildClickHandler };
return React.cloneElement(child as React.ReactElement<unknown>, childProps);
}, 'SignInButton');
const childProps = { ...rest, onClick: wrappedChildClickHandler };
return React.cloneElement(child as React.ReactElement<unknown>, childProps);
},
{ component: 'SignInButton', renderWhileLoading: true },
);
2 changes: 1 addition & 1 deletion packages/react/src/components/SignInWithMetamaskButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ export const SignInWithMetamaskButton = withClerk(
const childProps = { ...rest, onClick: wrappedChildClickHandler };
return React.cloneElement(child as React.ReactElement<unknown>, childProps);
},
'SignInWithMetamask',
{ component: 'SignInWithMetamask', renderWhileLoading: true },
);
2 changes: 1 addition & 1 deletion packages/react/src/components/SignOutButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ export const SignOutButton = withClerk(
const childProps = { ...rest, onClick: wrappedChildClickHandler };
return React.cloneElement(child as React.ReactElement<unknown>, childProps);
},
'SignOutButton',
{ component: 'SignOutButton', renderWhileLoading: true },
);
79 changes: 41 additions & 38 deletions packages/react/src/components/SignUpButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,52 @@ import type { SignUpButtonProps, WithClerkProp } from '../types';
import { assertSingleChild, normalizeWithDefaultValue, safeExecute } from '../utils';
import { withClerk } from './withClerk';

export const SignUpButton = withClerk(({ clerk, children, ...props }: WithClerkProp<SignUpButtonProps>) => {
const {
fallbackRedirectUrl,
forceRedirectUrl,
signInFallbackRedirectUrl,
signInForceRedirectUrl,
mode,
unsafeMetadata,
initialValues,
...rest
} = props;

children = normalizeWithDefaultValue(children, 'Sign up');
const child = assertSingleChild(children)('SignUpButton');

const clickHandler = () => {
const opts: SignUpProps = {
export const SignUpButton = withClerk(
({ clerk, children, ...props }: WithClerkProp<SignUpButtonProps>) => {
const {
fallbackRedirectUrl,
forceRedirectUrl,
signInFallbackRedirectUrl,
signInForceRedirectUrl,
mode,
unsafeMetadata,
initialValues,
...rest
} = props;

children = normalizeWithDefaultValue(children, 'Sign up');
const child = assertSingleChild(children)('SignUpButton');

const clickHandler = () => {
const opts: SignUpProps = {
fallbackRedirectUrl,
forceRedirectUrl,
signInFallbackRedirectUrl,
signInForceRedirectUrl,
unsafeMetadata,
initialValues,
};

if (mode === 'modal') {
return clerk.openSignUp(opts);
}

return clerk.redirectToSignUp({
...opts,
signUpFallbackRedirectUrl: fallbackRedirectUrl,
signUpForceRedirectUrl: forceRedirectUrl,
});
};

if (mode === 'modal') {
return clerk.openSignUp(opts);
}

return clerk.redirectToSignUp({
...opts,
signUpFallbackRedirectUrl: fallbackRedirectUrl,
signUpForceRedirectUrl: forceRedirectUrl,
});
};

const wrappedChildClickHandler: React.MouseEventHandler = async e => {
if (child && typeof child === 'object' && 'props' in child) {
await safeExecute(child.props.onClick)(e);
}
return clickHandler();
};

const childProps = { ...rest, onClick: wrappedChildClickHandler };
return React.cloneElement(child as React.ReactElement<unknown>, childProps);
}, 'SignUpButton');
const wrappedChildClickHandler: React.MouseEventHandler = async e => {
if (child && typeof child === 'object' && 'props' in child) {
await safeExecute(child.props.onClick)(e);
}
return clickHandler();
};

const childProps = { ...rest, onClick: wrappedChildClickHandler };
return React.cloneElement(child as React.ReactElement<unknown>, childProps);
},
{ component: 'SignUpButton', renderWhileLoading: true },
);

0 comments on commit 4e5825a

Please sign in to comment.