Skip to content

Commit 4847a2b

Browse files
committed
refactor(ui): Extract OAuth LogoGroup components
1 parent 529cf73 commit 4847a2b

4 files changed

Lines changed: 133 additions & 115 deletions

File tree

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { descriptors, Flex } from '@/ui/customizables';
2+
import type { ComponentProps } from 'react';
3+
import type { ThemableCssProp } from '@/ui/styledSystem';
4+
import { Box, Icon } from '@/ui/customizables';
5+
import { LockDottedCircle } from '@/ui/icons';
6+
import { colors } from '@/ui/utils/colors';
7+
import { common } from '@/ui/styledSystem';
8+
9+
export function LogoGroup({ children }: { children: React.ReactNode }) {
10+
return (
11+
<Flex
12+
justify='center'
13+
align='center'
14+
gap={4}
15+
sx={t => ({
16+
marginBlockEnd: t.space.$6,
17+
})}
18+
elementDescriptor={descriptors.logoGroup}
19+
>
20+
{children}
21+
</Flex>
22+
);
23+
}
24+
25+
export function LogoGroupItem({ children, sx, ...props }: ComponentProps<typeof Flex>) {
26+
return (
27+
<Flex
28+
{...props}
29+
sx={[{ flex: 1 }, sx]}
30+
elementDescriptor={descriptors.logoGroupItem}
31+
>
32+
{children}
33+
</Flex>
34+
);
35+
}
36+
37+
export function LogoGroupIcon({ size = 'md', sx }: { size?: 'sm' | 'md'; sx?: ThemableCssProp }) {
38+
const scale: ThemableCssProp = t => {
39+
const value = size === 'sm' ? t.space.$6 : t.space.$12;
40+
return {
41+
width: value,
42+
height: value,
43+
};
44+
};
45+
46+
return (
47+
<Box
48+
sx={t => [
49+
{
50+
background: common.mergedColorsBackground(
51+
colors.setAlpha(t.colors.$colorBackground, 1),
52+
t.colors.$neutralAlpha50,
53+
),
54+
borderRadius: t.radii.$circle,
55+
borderWidth: t.borderWidths.$normal,
56+
borderStyle: t.borderStyles.$solid,
57+
borderColor: t.colors.$borderAlpha100,
58+
display: 'flex',
59+
alignItems: 'center',
60+
justifyContent: 'center',
61+
},
62+
scale,
63+
sx,
64+
]}
65+
elementDescriptor={descriptors.logoGroupIcon}
66+
>
67+
<Icon
68+
icon={LockDottedCircle}
69+
sx={t => ({
70+
color: t.colors.$primary500,
71+
})}
72+
/>
73+
</Box>
74+
);
75+
}
76+
77+
export function LogoGroupSeparator() {
78+
return (
79+
<Box
80+
as='svg'
81+
// @ts-ignore - valid SVG attribute
82+
fill='none'
83+
viewBox='0 0 16 2'
84+
height={2}
85+
aria-hidden
86+
sx={t => ({
87+
color: t.colors.$colorMutedForeground,
88+
})}
89+
elementDescriptor={descriptors.logoGroupSeparator}
90+
>
91+
<path
92+
stroke='currentColor'
93+
strokeDasharray='0.1 4'
94+
strokeLinecap='round'
95+
strokeWidth='2'
96+
d='M1 1h14'
97+
/>
98+
</Box>
99+
);
100+
}

packages/ui/src/components/OAuthConsent/OAuthConsent.tsx

Lines changed: 23 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
11
import { useUser } from '@clerk/shared/react';
2-
import type { ComponentProps } from 'react';
32
import { useState } from 'react';
43

54
import { useEnvironment, useOAuthConsentContext } from '@/ui/contexts';
6-
import { Box, Button, Flex, Flow, Grid, Icon, Text } from '@/ui/customizables';
5+
import { Box, Button, Flow, Grid, Text } from '@/ui/customizables';
76
import { ApplicationLogo } from '@/ui/elements/ApplicationLogo';
87
import { Card } from '@/ui/elements/Card';
98
import { withCardStateProvider } from '@/ui/elements/contexts';
109
import { Header } from '@/ui/elements/Header';
1110
import { Modal } from '@/ui/elements/Modal';
1211
import { Tooltip } from '@/ui/elements/Tooltip';
13-
import { LockDottedCircle } from '@/ui/icons';
1412
import { Alert, Textarea } from '@/ui/primitives';
15-
import type { ThemableCssProp } from '@/ui/styledSystem';
1613
import { common } from '@/ui/styledSystem';
1714
import { colors } from '@/ui/utils/colors';
18-
15+
import { LogoGroup, LogoGroupItem, LogoGroupIcon, LogoGroupSeparator } from './LogoGroup';
1916
import { OrgSelect } from './OrgSelect';
2017

2118
const OFFLINE_ACCESS_SCOPE = 'offline_access';
@@ -61,24 +58,24 @@ export function OAuthConsentInternal() {
6158
<Header.Root>
6259
{/* both have avatars */}
6360
{oAuthApplicationLogoUrl && logoImageUrl && (
64-
<ConnectionHeader>
65-
<ConnectionItem justify='end'>
61+
<LogoGroup>
62+
<LogoGroupItem justify='end'>
6663
<ApplicationLogo
6764
src={oAuthApplicationLogoUrl}
6865
alt={oAuthApplicationName}
6966
href={oAuthApplicationUrl}
7067
isExternal
7168
/>
72-
</ConnectionItem>
73-
<ConnectionSeparator />
74-
<ConnectionItem justify='start'>
69+
</LogoGroupItem>
70+
<LogoGroupSeparator />
71+
<LogoGroupItem justify='start'>
7572
<ApplicationLogo />
76-
</ConnectionItem>
77-
</ConnectionHeader>
73+
</LogoGroupItem>
74+
</LogoGroup>
7875
)}
7976
{/* only OAuth app has an avatar */}
8077
{oAuthApplicationLogoUrl && !logoImageUrl && (
81-
<ConnectionHeader>
78+
<LogoGroup>
8279
<Box
8380
sx={{
8481
position: 'relative',
@@ -90,7 +87,7 @@ export function OAuthConsentInternal() {
9087
href={oAuthApplicationUrl}
9188
isExternal
9289
/>
93-
<ConnectionIcon
90+
<LogoGroupIcon
9491
size='sm'
9592
sx={t => ({
9693
position: 'absolute',
@@ -99,25 +96,25 @@ export function OAuthConsentInternal() {
9996
})}
10097
/>
10198
</Box>
102-
</ConnectionHeader>
99+
</LogoGroup>
103100
)}
104101
{/* only Clerk application has an avatar */}
105102
{!oAuthApplicationLogoUrl && logoImageUrl && (
106-
<ConnectionHeader>
107-
<ConnectionItem justify='end'>
108-
<ConnectionIcon />
109-
</ConnectionItem>
110-
<ConnectionSeparator />
111-
<ConnectionItem justify='start'>
103+
<LogoGroup>
104+
<LogoGroupItem justify='end'>
105+
<LogoGroupIcon />
106+
</LogoGroupItem>
107+
<LogoGroupSeparator />
108+
<LogoGroupItem justify='start'>
112109
<ApplicationLogo />
113-
</ConnectionItem>
114-
</ConnectionHeader>
110+
</LogoGroupItem>
111+
</LogoGroup>
115112
)}
116113
{/* no avatars */}
117114
{!oAuthApplicationLogoUrl && !logoImageUrl && (
118-
<ConnectionHeader>
119-
<ConnectionIcon />
120-
</ConnectionHeader>
115+
<LogoGroup>
116+
<LogoGroupIcon />
117+
</LogoGroup>
121118
)}
122119
<Header.Title localizationKey={oAuthApplicationName} />
123120
<Header.Subtitle localizationKey={`wants to access ${applicationName} on behalf of ${primaryIdentifier}`} />
@@ -325,93 +322,4 @@ function RedirectUriModal({ onOpen, onClose, isOpen, redirectUri, oAuthApplicati
325322
);
326323
}
327324

328-
function ConnectionHeader({ children }: { children: React.ReactNode }) {
329-
return (
330-
<Flex
331-
justify='center'
332-
align='center'
333-
gap={4}
334-
sx={t => ({
335-
marginBlockEnd: t.space.$6,
336-
})}
337-
>
338-
{children}
339-
</Flex>
340-
);
341-
}
342-
343-
function ConnectionItem({ children, sx, ...props }: ComponentProps<typeof Flex>) {
344-
return (
345-
<Flex
346-
{...props}
347-
sx={[{ flex: 1 }, sx]}
348-
>
349-
{children}
350-
</Flex>
351-
);
352-
}
353-
354-
function ConnectionIcon({ size = 'md', sx }: { size?: 'sm' | 'md'; sx?: ThemableCssProp }) {
355-
const scale: ThemableCssProp = t => {
356-
const value = size === 'sm' ? t.space.$6 : t.space.$12;
357-
return {
358-
width: value,
359-
height: value,
360-
};
361-
};
362-
363-
return (
364-
<Box
365-
sx={t => [
366-
{
367-
background: common.mergedColorsBackground(
368-
colors.setAlpha(t.colors.$colorBackground, 1),
369-
t.colors.$neutralAlpha50,
370-
),
371-
borderRadius: t.radii.$circle,
372-
borderWidth: t.borderWidths.$normal,
373-
borderStyle: t.borderStyles.$solid,
374-
borderColor: t.colors.$borderAlpha100,
375-
display: 'flex',
376-
alignItems: 'center',
377-
justifyContent: 'center',
378-
},
379-
scale,
380-
sx,
381-
]}
382-
>
383-
<Icon
384-
icon={LockDottedCircle}
385-
sx={t => ({
386-
color: t.colors.$primary500,
387-
})}
388-
/>
389-
</Box>
390-
);
391-
}
392-
393-
function ConnectionSeparator() {
394-
return (
395-
<Box
396-
as='svg'
397-
// @ts-ignore - valid SVG attribute
398-
fill='none'
399-
viewBox='0 0 16 2'
400-
height={2}
401-
aria-hidden
402-
sx={t => ({
403-
color: t.colors.$colorMutedForeground,
404-
})}
405-
>
406-
<path
407-
stroke='currentColor'
408-
strokeDasharray='0.1 4'
409-
strokeLinecap='round'
410-
strokeWidth='2'
411-
d='M1 1h14'
412-
/>
413-
</Box>
414-
);
415-
}
416-
417325
export const OAuthConsent = withCardStateProvider(OAuthConsentInternal);

packages/ui/src/customizables/elementDescriptors.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ export const APPEARANCE_KEYS = containsAllElementsConfigKeys([
5353
'logoBox',
5454
'logoImage',
5555

56+
'logoGroup',
57+
'logoGroupItem',
58+
'logoGroupIcon',
59+
'logoGroupSeparator',
60+
5661
'header',
5762
'headerTitle',
5863
'headerSubtitle',

packages/ui/src/internal/appearance.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ export type ElementsConfig = {
181181
logoBox: WithOptions;
182182
logoImage: WithOptions;
183183

184+
logoGroup: WithOptions;
185+
logoGroupItem: WithOptions;
186+
logoGroupIcon: WithOptions;
187+
logoGroupSeparator: WithOptions;
188+
184189
header: WithOptions;
185190
headerTitle: WithOptions;
186191
headerSubtitle: WithOptions;

0 commit comments

Comments
 (0)