Skip to content

Commit d54e42d

Browse files
authored
feat(elements): <Loading> component (clerk#3002)
* chore(repo): Update lock file * fix(elements): WIP * chore(elements): WIP * chore(elements): WIP * feat(elements): First sendParent * chore(elements): Add debug script to example * feat(elements): Get logic working * chore(elements): WIP * fix(elements): Remove unstable isLoading hook * fix(elements): Types * feat(elements): Make Loading component work * chore(elements): Stuff * feat(elements): More stuff * chore(elements): Revert formatting change * chore(elements): Add loading component to sign-up page * chore(elements): Export step types * feat(elements): Add Loading component for sign-up * feat(elements): Add shared sendToLoading action * chore(elements): Add sendToLoading test * fix(elements): Remove unintended change * chore(elements): Add JSDoc comments * chore(elements): Bump version * chore(repo): Update lock file * chore(elements): Bump version * feat(elements): Change isLoading function prop to be boolean, not object * chore(elements): Use Spinner in example * chore(elements): Bump version * fix(elements): Create scopeStrategy helper * feat(elements): Infer scope inside step * fix(elements): Add displayName * chore(elements): Bump version
1 parent f60829c commit d54e42d

39 files changed

Lines changed: 909 additions & 210 deletions

.changeset/violet-windows-turn.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

packages/elements/examples/nextjs/app/sign-in/[[...sign-in]]/page.tsx

Lines changed: 124 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { Field, FieldError, GlobalError, Input, Label } from '@clerk/elements/common';
44
import {
55
Action,
6+
Loading,
67
Provider,
78
ProviderIcon,
89
SafeIdentifier,
@@ -17,6 +18,7 @@ import { type ComponentProps, useState } from 'react';
1718

1819
import { H1, H3, P } from '@/components/design';
1920
import { CustomField } from '@/components/form';
21+
import { Spinner } from '@/components/spinner';
2022

2123
function CustomProvider({
2224
children,
@@ -26,15 +28,28 @@ function CustomProvider({
2628
provider: ComponentProps<typeof Provider>['name'];
2729
}) {
2830
return (
29-
<Provider
30-
name={provider}
31-
className='text-[rgb(243,243,243)] border-[rgb(37,37,37)] hover:border-[rgb(50,50,50)] [&>img]:opacity-80 [&>img]:hover:opacity-100 [&>img]:grayscale [&>img]:hover:grayscale-0 relative flex h-14 w-full cursor-pointer items-center justify-center rounded-lg border bg-[rgb(22,22,22)] hover:bg-[rgb(22,22,30)] text-sm transition-all duration-150'
32-
>
33-
<ProviderIcon
34-
className={`absolute left-4 transition-all duration-200${provider === 'github' ? ' invert' : ''}`}
35-
/>
36-
<span className='leading-loose'>{children}</span>
37-
</Provider>
31+
<Loading scope={`provider:${provider}`}>
32+
{isLoading => (
33+
<Provider
34+
name={provider}
35+
className='text-[rgb(243,243,243)] border-[rgb(37,37,37)] hover:border-[rgb(50,50,50)] [&>img]:opacity-80 [&>img]:hover:opacity-100 [&>img]:grayscale [&>img]:hover:grayscale-0 relative flex h-14 w-full cursor-pointer items-center justify-center rounded-lg border bg-[rgb(22,22,22)] hover:bg-[rgb(22,22,30)] text-sm transition-all duration-150'
36+
disabled={isLoading}
37+
>
38+
<ProviderIcon
39+
className={`absolute left-4 transition-all duration-200${provider === 'github' ? ' invert' : ''}`}
40+
/>
41+
<span className='leading-loose inline-flex justify-center items-center'>
42+
{isLoading ? (
43+
<>
44+
<Spinner /> Loading...
45+
</>
46+
) : (
47+
children
48+
)}
49+
</span>
50+
</Provider>
51+
)}
52+
</Loading>
3853
);
3954
}
4055

@@ -65,7 +80,7 @@ function Button({ children, ...props }: ComponentProps<'button'>) {
6580
function CustomSubmit({ children }: ComponentProps<'button'>) {
6681
return (
6782
<Action
68-
className='px-7 py-3 justify-center transition rounded-lg focus:outline-none border items-center disabled:bg-[rgb(12,12,12)] focus:text-[rgb(255,255,255)] w-full duration-300 focus:!border-[rgb(37,37,37)] text-sm space-x-1.5 text-[rgb(160,160,160)] hover:text-[rgb(243,243,243)] disabled:text-[rgb(100,100,100)] select-none bg-[rgb(22,22,22)] hover:bg-[rgb(22,22,30)] border-[rgb(37,37,37)] hover:border-[rgb(50,50,50)]'
83+
className='inline-flex px-7 py-3 justify-center transition rounded-lg focus:outline-none border items-center disabled:bg-[rgb(12,12,12)] focus:text-[rgb(255,255,255)] w-full duration-300 focus:!border-[rgb(37,37,37)] text-sm space-x-1.5 text-[rgb(160,160,160)] hover:text-[rgb(243,243,243)] disabled:text-[rgb(100,100,100)] select-none bg-[rgb(22,22,22)] hover:bg-[rgb(22,22,30)] border-[rgb(37,37,37)] hover:border-[rgb(50,50,50)]'
6984
submit
7085
>
7186
{children}
@@ -91,6 +106,9 @@ export default function SignInPage() {
91106
</Link>
92107
</p>
93108
</div>
109+
<div className='absolute top-4 right-4'>
110+
<Loading>{isLoading => <span>Loading: {JSON.stringify(isLoading, null, 2)}</span>}</Loading>
111+
</div>
94112

95113
<Step name='start'>
96114
<div className='flex flex-col items-center gap-12 w-96'>
@@ -116,7 +134,19 @@ export default function SignInPage() {
116134
<FieldError className='block text-red-400 font-mono w-full' />
117135
</Field>
118136

119-
<CustomSubmit>Sign in with Email</CustomSubmit>
137+
<CustomSubmit>
138+
<Loading>
139+
{isLoading =>
140+
isLoading ? (
141+
<>
142+
<Spinner /> Loading...
143+
</>
144+
) : (
145+
'Sign in with Email'
146+
)
147+
}
148+
</Loading>
149+
</CustomSubmit>
120150
</>
121151
) : (
122152
<TextButton onClick={() => setContinueWithEmail(true)}>Continue with Email</TextButton>
@@ -170,62 +200,90 @@ export default function SignInPage() {
170200
</Step>
171201

172202
<Step name='verifications'>
173-
<div className='flex gap-6 flex-col'>
174-
<GlobalError className='block text-red-400 font-mono' />
203+
<Loading>
204+
{isLoading => (
205+
<div className='flex gap-6 flex-col'>
206+
<GlobalError className='block text-red-400 font-mono' />
207+
208+
<Strategy name='password'>
209+
<P className='text-sm'>
210+
Welcome back <Salutation />!
211+
</P>
212+
213+
<CustomField
214+
label='Password'
215+
name='password'
216+
/>
175217

176-
<Strategy name='password'>
177-
<P className='text-sm'>
178-
Welcome back <Salutation />!
179-
</P>
180-
181-
<CustomField
182-
label='Password'
183-
name='password'
184-
/>
185-
186-
<CustomSubmit>Verify</CustomSubmit>
187-
</Strategy>
188-
189-
<Strategy name='email_code'>
190-
<P className='text-sm'>
191-
Welcome back! We&apos;ve sent a temporary code to <SafeIdentifier />
192-
</P>
193-
194-
<CustomField
195-
// eslint-disable-next-line jsx-a11y/no-autofocus
196-
autoFocus
197-
autoSubmit
198-
label='Email Code'
199-
name='code'
200-
/>
201-
202-
<CustomSubmit>Verify</CustomSubmit>
203-
</Strategy>
204-
205-
<Strategy name='phone_code'>
206-
<P className='text-sm'>
207-
Welcome back! We&apos;ve sent a temporary code to <SafeIdentifier />
208-
</P>
209-
210-
<CustomField
211-
// eslint-disable-next-line jsx-a11y/no-autofocus
212-
autoFocus
213-
autoSubmit
214-
label='Phone Code'
215-
name='code'
216-
/>
217-
218-
<CustomSubmit>Verify</CustomSubmit>
219-
</Strategy>
220-
221-
<Strategy name='reset_password_email_code'>
222-
<H3>Verify your email</H3>
223-
224-
<P className='text-sm'>
225-
We&apos;ve sent a verification code to <SafeIdentifier />.
226-
</P>
227-
</Strategy>
228-
</div>
218+
<CustomSubmit>
219+
{isLoading ? (
220+
<>
221+
<Spinner /> Loading...
222+
</>
223+
) : (
224+
'Verify'
225+
)}
226+
</CustomSubmit>
227+
</Strategy>
228+
229+
<Strategy name='email_code'>
230+
<P className='text-sm'>
231+
Welcome back! We&apos;ve sent a temporary code to <SafeIdentifier />
232+
</P>
233+
234+
<CustomField
235+
// eslint-disable-next-line jsx-a11y/no-autofocus
236+
autoFocus
237+
autoSubmit
238+
label='Email Code'
239+
name='code'
240+
/>
241+
242+
<CustomSubmit>
243+
{isLoading ? (
244+
<>
245+
<Spinner /> Loading...
246+
</>
247+
) : (
248+
'Verify'
249+
)}
250+
</CustomSubmit>
251+
</Strategy>
252+
253+
<Strategy name='phone_code'>
254+
<P className='text-sm'>
255+
Welcome back! We&apos;ve sent a temporary code to <SafeIdentifier />
256+
</P>
257+
258+
<CustomField
259+
// eslint-disable-next-line jsx-a11y/no-autofocus
260+
autoFocus
261+
autoSubmit
262+
label='Phone Code'
263+
name='code'
264+
/>
265+
266+
<CustomSubmit>
267+
{isLoading ? (
268+
<>
269+
<Spinner /> Loading...
270+
</>
271+
) : (
272+
'Verify'
273+
)}
274+
</CustomSubmit>
275+
</Strategy>
276+
277+
<Strategy name='reset_password_email_code'>
278+
<H3>Verify your email</H3>
279+
280+
<P className='text-sm'>
281+
We&apos;ve sent a verification code to <SafeIdentifier />.
282+
</P>
283+
</Strategy>
284+
</div>
285+
)}
286+
</Loading>
229287

230288
<Action
231289
asChild

packages/elements/examples/nextjs/app/sign-up/[[...sign-up]]/page.tsx

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
'use client';
22

33
import { GlobalError } from '@clerk/elements/common';
4-
import { Action, Provider, ProviderIcon, SignUp, Step, Strategy } from '@clerk/elements/sign-up';
4+
import { Action, Loading, Provider, ProviderIcon, SignUp, Step, Strategy } from '@clerk/elements/sign-up';
55
import type { ComponentProps } from 'react';
66

77
import { H1, HR as Hr } from '@/components/design';
88
import { CustomField } from '@/components/form';
9+
import { Spinner } from '@/components/spinner';
910

1011
function CustomSubmit({ children }: ComponentProps<'button'>) {
1112
return (
1213
<Action
13-
className='px-7 py-3 justify-center transition rounded-lg focus:outline-none border items-center disabled:bg-[rgb(12,12,12)] focus:text-[rgb(255,255,255)] w-full duration-300 focus:!border-[rgb(37,37,37)] text-sm space-x-1.5 text-[rgb(160,160,160)] hover:text-[rgb(243,243,243)] disabled:text-[rgb(100,100,100)] select-none bg-[rgb(22,22,22)] hover:bg-[rgb(22,22,30)] border-[rgb(37,37,37)] hover:border-[rgb(50,50,50)]'
14+
className='inline-flex px-7 py-3 justify-center transition rounded-lg focus:outline-none border items-center disabled:bg-[rgb(12,12,12)] focus:text-[rgb(255,255,255)] w-full duration-300 focus:!border-[rgb(37,37,37)] text-sm space-x-1.5 text-[rgb(160,160,160)] hover:text-[rgb(243,243,243)] disabled:text-[rgb(100,100,100)] select-none bg-[rgb(22,22,22)] hover:bg-[rgb(22,22,30)] border-[rgb(37,37,37)] hover:border-[rgb(50,50,50)]'
1415
submit
1516
>
1617
{children}
@@ -66,7 +67,19 @@ export default function SignUpPage() {
6667
label='Phone Number'
6768
name='phoneNumber'
6869
/>
69-
<CustomSubmit>Sign Up</CustomSubmit>
70+
<CustomSubmit>
71+
<Loading>
72+
{isLoading =>
73+
isLoading ? (
74+
<>
75+
<Spinner /> Loading...
76+
</>
77+
) : (
78+
'Sign Up'
79+
)
80+
}
81+
</Loading>
82+
</CustomSubmit>
7083
</div>
7184
</div>
7285
</Step>
@@ -87,7 +100,19 @@ export default function SignUpPage() {
87100
name='phoneNumber'
88101
/>
89102

90-
<CustomSubmit>Sign Up</CustomSubmit>
103+
<CustomSubmit>
104+
<Loading>
105+
{isLoading =>
106+
isLoading ? (
107+
<>
108+
<Spinner /> Loading...
109+
</>
110+
) : (
111+
'Sign Up'
112+
)
113+
}
114+
</Loading>
115+
</CustomSubmit>
91116
</Step>
92117

93118
<Step name='verifications'>
@@ -101,7 +126,19 @@ export default function SignUpPage() {
101126
name='code'
102127
/>
103128

104-
<CustomSubmit>Verify</CustomSubmit>
129+
<CustomSubmit>
130+
<Loading>
131+
{isLoading =>
132+
isLoading ? (
133+
<>
134+
<Spinner /> Loading...
135+
</>
136+
) : (
137+
'Verify'
138+
)
139+
}
140+
</Loading>
141+
</CustomSubmit>
105142
</Strategy>
106143

107144
<Strategy name='email_code'>
@@ -110,7 +147,19 @@ export default function SignUpPage() {
110147
name='code'
111148
/>
112149

113-
<CustomSubmit>Verify</CustomSubmit>
150+
<CustomSubmit>
151+
<Loading>
152+
{isLoading =>
153+
isLoading ? (
154+
<>
155+
<Spinner /> Loading...
156+
</>
157+
) : (
158+
'Verify'
159+
)
160+
}
161+
</Loading>
162+
</CustomSubmit>
114163
</Strategy>
115164

116165
<Strategy name='email_link'>Please check your email for a link to verify your account.</Strategy>

0 commit comments

Comments
 (0)