Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(elements): Add temporary useIsLoading hook #2751

Merged
merged 12 commits into from
Feb 14, 2024
2 changes: 2 additions & 0 deletions .changeset/hip-monkeys-boil.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { SignIn, SocialProvider, SocialProviderIcon, Start, Verification, Verify

import { H1, H3, HR as Hr, P } from '@/components/design';
import { CustomField, CustomSubmit } from '@/components/form';
import { Loading } from '@/components/loader';

export default function SignInPage() {
return (
Expand Down Expand Up @@ -45,10 +46,12 @@ export default function SignInPage() {
<Hr />

<div className='flex gap-6 flex-col'>
<CustomField
label='Email'
name='identifier'
/>
<Loading>
<CustomField
label='Email'
name='identifier'
/>
</Loading>

{/* <Hr />

Expand All @@ -68,44 +71,46 @@ export default function SignInPage() {

<GlobalError className='block text-red-400 font-mono' />

<Verification name='password'>
<CustomField
label='Password'
name='password'
/>

<CustomSubmit>Sign In</CustomSubmit>
</Verification>

<Verification name='email_code'>
<CustomField
label='Email Code'
name='code'
/>

<CustomSubmit>Sign In</CustomSubmit>
</Verification>

<Verification name='phone_code'>
<CustomField
label='Phone Code'
name='code'
/>

<Submit className='px-4 py-2 b-1 bg-blue-950 bg-opacity-20 hover:bg-opacity-10 active:bg-opacity-5 rounded-md dark:bg-opacity-100 dark:hover:bg-opacity-80 dark:active:bg-opacity-50 transition'>
Sign In
</Submit>
</Verification>

<Verification name='reset_password_email_code'>
<H3>Verify your email</H3>

<P>Please check your email for a verification code...</P>

<Submit className='px-4 py-2 b-1 bg-blue-950 bg-opacity-20 hover:bg-opacity-10 active:bg-opacity-5 rounded-md dark:bg-opacity-100 dark:hover:bg-opacity-80 dark:active:bg-opacity-50 transition'>
Verify
</Submit>
</Verification>
<Loading>
<Verification name='password'>
<CustomField
label='Password'
name='password'
/>

<CustomSubmit>Sign In</CustomSubmit>
</Verification>

<Verification name='email_code'>
<CustomField
label='Email Code'
name='code'
/>

<CustomSubmit>Sign In</CustomSubmit>
</Verification>

<Verification name='phone_code'>
<CustomField
label='Phone Code'
name='code'
/>

<Submit className='px-4 py-2 b-1 bg-blue-950 bg-opacity-20 hover:bg-opacity-10 active:bg-opacity-5 rounded-md dark:bg-opacity-100 dark:hover:bg-opacity-80 dark:active:bg-opacity-50 transition'>
Sign In
</Submit>
</Verification>

<Verification name='reset_password_email_code'>
<H3>Verify your email</H3>

<P>Please check your email for a verification code...</P>

<Submit className='px-4 py-2 b-1 bg-blue-950 bg-opacity-20 hover:bg-opacity-10 active:bg-opacity-5 rounded-md dark:bg-opacity-100 dark:hover:bg-opacity-80 dark:active:bg-opacity-50 transition'>
Verify
</Submit>
</Verification>
</Loading>
</div>
</Verify>
</div>
Expand Down
64 changes: 64 additions & 0 deletions packages/elements/examples/nextjs/components/loader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
'use client';
import { unstable_useIsLoading } from '@clerk/elements/sign-in';
import { motion } from 'framer-motion';

const colors = ['#22238f', '#6b45fa', '#ca3286', '#fe2b49', '#fe652d'];

const containerVariants = {
initial: {},
animate: {
transition: {
when: 'beforeChildren',
staggerChildren: 0.1,
},
},
};

const dotVariants = {
initial: {},
animate: {
height: [20, 40, 20],
transition: {
repeat: Infinity,
},
},
};

const Loader = ({ count = 5 }) => {
return (
<motion.div
variants={containerVariants}
initial='initial'
animate='animate'
style={{
display: 'flex',
gap: 10,
height: 40,
alignItems: 'center',
}}
>
{Array(count)
.fill(null)
.map((_, index) => {
return (
<motion.div
key={index}
variants={dotVariants}
style={{
height: 20,
width: 20,
backgroundColor: colors[index % colors.length],
borderRadius: 20,
}}
/>
);
})}
</motion.div>
);
};

export function Loading({ children }: { children: React.ReactNode }) {
const [isLoading] = unstable_useIsLoading();

return isLoading ? <Loader /> : children;
}
33 changes: 33 additions & 0 deletions packages/elements/src/react/hooks/use-loading.hook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { useActiveTags } from '~/react/hooks/use-active-tags.hook';
import { SignInStartCtx } from '~/react/sign-in/start';
import { SignInFirstFactorCtx, SignInSecondFactorCtx } from '~/react/sign-in/verifications';

/**
* Caution: This hook is unstable and may disappear in the future.
* This is a temporary hook until the actual loading API is explored and implemented.
*/
export const unstable_useIsLoading = () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To keep with React hook naming conventions:

Suggested change
export const unstable_useIsLoading = () => {
export const useIsLoading_unstable = () => {

let startLoading = false;
let firstFactorLoading = false;
let secondFactorLoading = false;

const startRef = SignInStartCtx.useActorRef(true);
if (startRef) {
startLoading = useActiveTags(startRef, 'state:loading');
}

const firstFactorRef = SignInFirstFactorCtx.useActorRef(true);
if (firstFactorRef) {
firstFactorLoading = useActiveTags(firstFactorRef, 'state:loading');
}

const secondFactorRef = SignInSecondFactorCtx.useActorRef(true);
if (secondFactorRef) {
secondFactorLoading = useActiveTags(secondFactorRef, 'state:loading');
}

const isGlobalLoading = startLoading || firstFactorLoading || secondFactorLoading;

return [isGlobalLoading, { start: startLoading, firstFactor: firstFactorLoading, secondFactor: secondFactorLoading }];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likely a cleaner/clearer way to handle this in the long-run, but cool for now. On concern though is that it's specific to signIn, and lives in the root React hooks. Mind moving it over?

};
2 changes: 2 additions & 0 deletions packages/elements/src/react/sign-in/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export {
SignInVerify as Verify,
} from './verifications';

export { unstable_useIsLoading } from '../hooks/use-loading.hook';

/** @internal Internal use only */
export const useSignInActorRef_internal = SignInRouterCtx.useActorRef;

Expand Down
2 changes: 1 addition & 1 deletion packages/elements/src/react/utils/xstate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export function createConsoleInspector(): Observer<InspectionEvent> {
}
}

const defaults = 'font-weight: bold; line-height: 2; border-radius: 8px; padding: 6px 10px;';
const defaults = 'font-weight: bold; line-height: 1.5; border-radius: 8px; padding: 4px 10px;';
const reset = 'color: inherit;';

const Styles = {
Expand Down
Loading