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 @@
---
---
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {

import { H1, H2, H3, HR as Hr, P } from '@/components/design';
import { CustomField, CustomSubmit } from '@/components/form';
import { Loading } from '@/components/loader';
import { SignInDebug } from '@/components/sign-in-debug';

export default function SignInPage() {
Expand Down Expand Up @@ -54,10 +55,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 @@ -79,48 +82,49 @@ export default function SignInPage() {
Current Factor: <Factor first>First</Factor> | <Factor second>Second</Factor>
</H2>

<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>
</Continue>
</div>

<SignInDebug />
</SignIn>
);
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;
}
2 changes: 1 addition & 1 deletion packages/elements/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@clerk/elements",
"version": "0.1.2",
"version": "0.1.3",
"description": "Clerk Elements",
"keywords": [
"clerk",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export interface SignInMachineInput {
signUpPath: string;
}

export type SignInMachineTags = 'state:start' | 'state:first-factor' | 'state:second-factor' | 'external';
export type SignInMachineTags = 'state:start' | 'state:first-factor' | 'state:second-factor' | 'external' | 'loading';

export type SignInMachineEvents =
| ErrorActorEvent
Expand Down Expand Up @@ -247,7 +247,7 @@ export const SignInMachine = setup({
},
Start: {
id: 'Start',
tags: 'state:start',
tags: ['state:start'],
LekoArts marked this conversation as resolved.
Show resolved Hide resolved
description: 'The initial state of the sign-in flow.',
initial: 'AwaitingInput',
on: {
Expand Down Expand Up @@ -287,6 +287,7 @@ export const SignInMachine = setup({
},
},
Attempting: {
tags: ['loading'],
invoke: {
id: 'createSignIn',
src: 'createSignIn',
Expand Down Expand Up @@ -328,7 +329,7 @@ export const SignInMachine = setup({
always: [
{
description: 'If the current factor is not password, prepare the factor',
guard: not('isCurrentFactorPassword'),
guard: and([not('isCurrentFactorPassword'), { type: 'isCurrentPath', params: { path: '/continue' } }]),
target: 'Preparing',
},
{
Expand All @@ -338,6 +339,7 @@ export const SignInMachine = setup({
],
},
Preparing: {
tags: ['loading'],
invoke: {
id: 'prepareFirstFactor',
src: 'prepareFirstFactor',
Expand Down Expand Up @@ -372,6 +374,7 @@ export const SignInMachine = setup({
},
},
Attempting: {
tags: ['loading'],
invoke: {
id: 'attemptFirstFactor',
src: 'attemptFirstFactor',
Expand All @@ -398,7 +401,7 @@ export const SignInMachine = setup({
},
},
SecondFactor: {
tags: 'state:second-factor',
tags: ['state:second-factor'],
initial: 'DeterminingState',
entry: [{ type: 'navigateTo', params: { path: '/continue' } }, 'assignStartingSecondFactor'],
onDone: [
Expand All @@ -412,7 +415,7 @@ export const SignInMachine = setup({
always: [
{
description: 'If the current factor is not TOTP, prepare the factor',
guard: not('isCurrentFactorTOTP'),
guard: and([not('isCurrentFactorTOTP'), { type: 'isCurrentPath', params: { path: '/continue' } }]),
target: 'Preparing',
reenter: true,
},
Expand All @@ -424,6 +427,7 @@ export const SignInMachine = setup({
],
},
Preparing: {
tags: ['loading'],
invoke: {
id: 'prepareSecondFactor',
src: 'prepareSecondFactor',
Expand Down Expand Up @@ -451,6 +455,7 @@ export const SignInMachine = setup({
},
},
Attempting: {
tags: ['loading'],
invoke: {
id: 'attemptSecondFactor',
src: 'attemptSecondFactor',
Expand Down Expand Up @@ -481,6 +486,7 @@ export const SignInMachine = setup({
},
},
AuthenticatingWithRedirect: {
tags: ['loading'],
invoke: {
id: 'authenticateWithSignInRedirect',
src: 'authenticateWithSignInRedirect',
Expand Down Expand Up @@ -515,7 +521,7 @@ export const SignInMachine = setup({
},
},
SSOCallback: {
tags: 'external',
tags: ['external'],
initial: 'Attempting',
on: {
'CLERKJS.NAVIGATE.COMPLETE': '#SignIn.Complete',
Expand Down Expand Up @@ -555,6 +561,7 @@ export const SignInMachine = setup({
},
states: {
Attempting: {
tags: ['loading'],
invoke: {
id: 'handleRedirectCallback',
src: 'handleRedirectCallback',
Expand Down
13 changes: 13 additions & 0 deletions packages/elements/src/react/sign-in/hooks/use-loading.hook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { useActiveTags } from '~/react/hooks/use-active-tags.hook';
import { SignInCtx } from '~/react/sign-in/contexts/sign-in.context';

/**
* 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 = () => {
const ref = SignInCtx.useActorRef();

return useActiveTags(ref, 'loading');
};
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 @@ -11,6 +11,8 @@ export {
export { SignInStart as Start } from './start';
export { SignInFactor as Factor, SignInVerification as Verification } from './verifications';

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

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

Expand Down
Loading