Skip to content

Commit f53bf15

Browse files
authored
feat(ui): Sign out of other sessions checkbox (clerk#3801)
1 parent da21138 commit f53bf15

4 files changed

Lines changed: 86 additions & 13 deletions

File tree

.changeset/unlucky-yaks-turn.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import * as Common from '@clerk/elements/common';
2+
import React from 'react';
3+
4+
import * as Field from '../primitives/field';
5+
6+
export function CheckboxField({
7+
label,
8+
name,
9+
...props
10+
}: { name: React.ComponentProps<typeof Common.Field>['name']; label: React.ReactNode } & Omit<
11+
React.ComponentProps<typeof Common.Input>,
12+
'className' | 'type'
13+
>) {
14+
return (
15+
<Common.Field
16+
name={name}
17+
asChild
18+
>
19+
<Field.Root>
20+
<div className='flex gap-2'>
21+
<Common.Input
22+
type='checkbox'
23+
asChild
24+
{...props}
25+
>
26+
<Field.Checkbox />
27+
</Common.Input>
28+
29+
<Common.Label asChild>
30+
<Field.Label>{label}</Field.Label>
31+
</Common.Label>
32+
</div>
33+
34+
<Common.FieldError asChild>
35+
{({ message }) => {
36+
return <Field.Message intent='error'>{message}</Field.Message>;
37+
}}
38+
</Common.FieldError>
39+
</Field.Root>
40+
</Common.Field>
41+
);
42+
}

packages/ui/src/components/sign-in/sign-in.tsx

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as SignIn from '@clerk/elements/sign-in';
44
import * as React from 'react';
55

66
import { BackupCodeField } from '~/common/backup-code-field';
7+
import { CheckboxField } from '~/common/checkbox-field';
78
import { Connections } from '~/common/connections';
89
import { EmailField } from '~/common/email-field';
910
import { EmailOrPhoneNumberField } from '~/common/email-or-phone-number-field';
@@ -1141,28 +1142,36 @@ export function SignInComponentLoaded() {
11411142
return <Alert>{message}</Alert>;
11421143
}}
11431144
</Common.GlobalError>
1144-
<div className='flex flex-col justify-center gap-4'>
1145-
<PasswordField
1146-
validatePassword
1147-
name='password'
1148-
label={t('formFieldLabel__newPassword')}
1149-
/>
1150-
<PasswordField
1151-
name='confirmPassword'
1152-
label={t('formFieldLabel__confirmPassword')}
1153-
/>
1145+
<div className='flex flex-col justify-center gap-6'>
1146+
<div className='flex flex-col justify-center gap-4'>
1147+
<PasswordField
1148+
validatePassword
1149+
name='password'
1150+
label={t('formFieldLabel__newPassword')}
1151+
/>
1152+
<PasswordField
1153+
name='confirmPassword'
1154+
label={t('formFieldLabel__confirmPassword')}
1155+
/>
11541156

1157+
<CheckboxField
1158+
name='signOutOfOtherSessions'
1159+
label={t('formFieldLabel__signOutOfOtherSessions')}
1160+
defaultChecked
1161+
/>
1162+
</div>
11551163
<Common.Loading>
11561164
{isSubmitting => {
11571165
return (
1158-
<>
1166+
<div className='flex flex-col justify-center gap-4'>
11591167
<SignIn.Action
11601168
submit
11611169
asChild
11621170
>
11631171
<Button
11641172
busy={isSubmitting}
11651173
disabled={isGlobalLoading || isSubmitting}
1174+
spinnerWhenBusy
11661175
>
11671176
{t('signIn.resetPassword.formButtonPrimary')}
11681177
</Button>
@@ -1174,7 +1183,7 @@ export function SignInComponentLoaded() {
11741183
>
11751184
<LinkButton>{t('backButton')}</LinkButton>
11761185
</SignIn.Action>
1177-
</>
1186+
</div>
11781187
);
11791188
}}
11801189
</Common.Loading>

packages/ui/src/primitives/field.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const Root = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDi
1515
ref={forwardedRef}
1616
{...props}
1717
className={cx(
18+
'has-[[data-field-checkbox]]:[--cl-field-label-cursor:pointer]',
1819
'has-[[data-field-input][disabled]]:[--cl-field-label-opacity:0.5]',
1920
'flex flex-col gap-2',
2021
className,
@@ -41,7 +42,11 @@ export const Label = React.forwardRef(function Label(
4142
className={cx(
4243
visuallyHidden
4344
? 'sr-only'
44-
: 'text-gray-12 flex items-center gap-x-1 text-base font-medium opacity-[--cl-field-label-opacity,1]',
45+
: [
46+
'text-gray-12 flex items-center gap-x-1 text-base font-medium opacity-[--cl-field-label-opacity,1]',
47+
'cursor-[--cl-field-label-cursor,auto]',
48+
],
49+
4550
className,
4651
)}
4752
>
@@ -80,6 +85,21 @@ export const Hint = React.forwardRef(function Hint(
8085
);
8186
});
8287

88+
export const Checkbox = React.forwardRef(function FieldCheckbox(
89+
props: React.InputHTMLAttributes<HTMLInputElement>,
90+
forwardedRef: React.ForwardedRef<HTMLInputElement>,
91+
) {
92+
return (
93+
<input
94+
ref={forwardedRef}
95+
type='checkbox'
96+
data-field-checkbox
97+
className={cx('accent-accent-9 mt-[0.1875em] size-3 cursor-pointer')}
98+
{...props}
99+
/>
100+
);
101+
});
102+
83103
export const Input = React.forwardRef(function Input(
84104
{
85105
asChild,

0 commit comments

Comments
 (0)