Skip to content
5 changes: 5 additions & 0 deletions .changeset/chilly-ravens-cover.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/clerk-js': patch
---

Refactor ApplicationLogo rendering logic to account for oAuth logos within OAuthConsent component.
2 changes: 1 addition & 1 deletion packages/clerk-js/bundlewatch.config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"files": [
{ "path": "./dist/clerk.js", "maxSize": "621KB" },
{ "path": "./dist/clerk.js", "maxSize": "621.1KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "75KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "117KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "57KB" },
Expand Down
75 changes: 42 additions & 33 deletions packages/clerk-js/src/ui/components/OAuthConsent/OAuthConsent.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useUser } from '@clerk/shared/react';
import type { ComponentProps } from 'react';
import { useState } from 'react';

import { useEnvironment, useOAuthConsentContext } from '@/ui/contexts';
import { Box, Button, Flex, Flow, Grid, Icon, Text } from '@/ui/customizables';
import { ApplicationLogo } from '@/ui/elements/ApplicationLogo';
import { Avatar } from '@/ui/elements/Avatar';
import { Card } from '@/ui/elements/Card';
import { withCardStateProvider } from '@/ui/elements/contexts';
import { Header } from '@/ui/elements/Header';
Expand All @@ -17,8 +17,14 @@ import { common } from '@/ui/styledSystem';
import { colors } from '@/ui/utils/colors';

export function OAuthConsentInternal() {
const { scopes, oAuthApplicationName, oAuthApplicationLogoUrl, redirectUrl, onDeny, onAllow } =
useOAuthConsentContext();
const {
scopes,
oAuthApplicationName,
oAuthApplicationLogoUrl = 'https://img.clerk.com/eyJ0eXBlIjoicHJveHkiLCJzcmMiOiJodHRwczovL2ltYWdlcy5jbGVyay5kZXYvdXBsb2FkZWQvaW1nXzMxOHVMSERjc0hTNXNaWlF0MlFEeWxpMER0RyJ9?width=400',
redirectUrl,
onDeny,
onAllow,
} = useOAuthConsentContext();
const { user } = useUser();
const { applicationName, logoImageUrl } = useEnvironment().displayConfig;
const [isUriModalOpen, setIsUriModalOpen] = useState(false);
Expand All @@ -42,13 +48,16 @@ export function OAuthConsentInternal() {
{/* both have avatars */}
{oAuthApplicationLogoUrl && logoImageUrl && (
<ConnectionHeader>
<Avatar
imageUrl={oAuthApplicationLogoUrl}
size={t => t.space.$12}
rounded={false}
/>
<ConnectionItem justify='end'>
<ApplicationLogo
src={oAuthApplicationLogoUrl}
alt={oAuthApplicationName}
/>
</ConnectionItem>
<ConnectionSeparator />
<ApplicationLogo />
<ConnectionItem justify='start'>
<ApplicationLogo />
</ConnectionItem>
</ConnectionHeader>
)}
{/* only OAuth app has an avatar */}
Expand All @@ -59,10 +68,9 @@ export function OAuthConsentInternal() {
position: 'relative',
}}
>
<Avatar
imageUrl={oAuthApplicationLogoUrl}
size={t => t.space.$12}
rounded={false}
<ApplicationLogo
src={oAuthApplicationLogoUrl}
alt={oAuthApplicationName}
/>
<ConnectionIcon
size='sm'
Expand All @@ -77,31 +85,21 @@ export function OAuthConsentInternal() {
)}
{/* only Clerk application has an avatar */}
{!oAuthApplicationLogoUrl && logoImageUrl && (
<Flex
justify='center'
align='center'
gap={4}
sx={t => ({
marginBlockEnd: t.space.$6,
})}
>
<ConnectionIcon />
<ConnectionHeader>
<ConnectionItem justify='end'>
<ConnectionIcon />
</ConnectionItem>
<ConnectionSeparator />
<ApplicationLogo />
</Flex>
<ConnectionItem justify='start'>
<ApplicationLogo />
</ConnectionItem>
</ConnectionHeader>
)}
{/* no avatars */}
{!oAuthApplicationLogoUrl && !logoImageUrl && (
<Flex
justify='center'
align='center'
gap={4}
sx={t => ({
marginBlockEnd: t.space.$6,
})}
>
<ConnectionHeader>
<ConnectionIcon />
</Flex>
</ConnectionHeader>
)}
<Header.Title localizationKey={oAuthApplicationName} />
<Header.Subtitle
Expand Down Expand Up @@ -320,6 +318,17 @@ function ConnectionHeader({ children }: { children: React.ReactNode }) {
);
}

function ConnectionItem({ children, ...props }: ComponentProps<typeof Flex>) {
return (
<Flex
{...props}
sx={[{ flex: 1 }, props.sx]}
>
{children}
</Flex>
);
}

function ConnectionIcon({ size = 'md', sx }: { size?: 'sm' | 'md'; sx?: ThemableCssProp }) {
const scale: ThemableCssProp = t => {
const value = size === 'sm' ? t.space.$6 : t.space.$12;
Expand Down
33 changes: 23 additions & 10 deletions packages/clerk-js/src/ui/elements/ApplicationLogo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,30 @@ const getContainerHeightForImageRatio = (imageRef: React.RefObject<HTMLImageElem
return width;
};

type ApplicationLogoProps = PropsOfComponent<typeof Flex>;
export type ApplicationLogoProps = PropsOfComponent<typeof Flex> & {
/**
* The URL of the image to display.
*/
src?: string;
/**
* The alt text for the image.
*/
alt?: string;
/**
* The URL to navigate to when the logo is clicked.
*/
href?: string;
};

export const ApplicationLogo = (props: ApplicationLogoProps) => {
export const ApplicationLogo: React.FC<ApplicationLogoProps> = (props: ApplicationLogoProps): JSX.Element | null => {
const { src, alt, href, sx, ...rest } = props;
const imageRef = React.useRef<HTMLImageElement>(null);
const [loaded, setLoaded] = React.useState(false);
const { logoImageUrl, applicationName, homeUrl } = useEnvironment().displayConfig;
const { parsedLayout } = useAppearance();
const imageSrc = parsedLayout.logoImageUrl || logoImageUrl;
const logoUrl = parsedLayout.logoLinkUrl || homeUrl;
const imageSrc = src || parsedLayout.logoImageUrl || logoImageUrl;
const imageAlt = alt || applicationName;
const logoUrl = href || parsedLayout.logoLinkUrl || homeUrl;

if (!imageSrc) {
return null;
Expand All @@ -39,7 +54,7 @@ export const ApplicationLogo = (props: ApplicationLogoProps) => {
<Image
ref={imageRef}
elementDescriptor={descriptors.logoImage}
alt={applicationName}
alt={imageAlt}
src={imageSrc}
size={200}
onLoad={() => setLoaded(true)}
Expand All @@ -55,20 +70,18 @@ export const ApplicationLogo = (props: ApplicationLogoProps) => {
return (
<Flex
elementDescriptor={descriptors.logoBox}
{...props}
{...rest}
sx={[
theme => ({
height: getContainerHeightForImageRatio(imageRef, theme.sizes.$6),
justifyContent: 'center',
}),
props.sx,
sx,
]}
>
{logoUrl ? (
<RouterLink
sx={{
justifyContent: 'center',
}}
focusRing
to={logoUrl}
>
{image}
Expand Down
9 changes: 9 additions & 0 deletions packages/clerk-js/src/ui/primitives/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,19 @@ const { applyVariants, filterProps } = createVariants(theme => ({
},
inherit: { color: 'inherit' },
},
focusRing: {
true: {
'&:focus': {
outline: 'none',
...common.focusRing(theme),
},
},
},
},
defaultVariants: {
colorScheme: 'primary',
variant: 'body',
focusRing: false,
},
}));

Expand Down
Loading