Skip to content

Commit 568186c

Browse files
octoperdesiprisganagstef
authored
feat(clerk-js): Add dev mode warning to components (#3511) (#3870)
Co-authored-by: George Desipris <george.desipris.56@gmail.com> Co-authored-by: Stefanos Anagnostou <anagstef@users.noreply.github.com>
1 parent 6909a42 commit 568186c

File tree

17 files changed

+240
-54
lines changed

17 files changed

+240
-54
lines changed

.changeset/hungry-clouds-return.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
'@clerk/clerk-js': minor
3+
"@clerk/types": minor
4+
---
5+
6+
Introducing a development mode warning when in development mode in order to mitigate going to production with development keys.
7+
8+
In case need to deactivate this UI change temporarily to simulate how components will look in production, you can do so by adding the `unsafe_disableDevelopmentModeWarnings` layout appearance prop to `<ClerkProvider>`
9+
10+
Example:
11+
12+
```tsx
13+
<ClerkProvider
14+
appearance={{
15+
layout: {
16+
unsafe_disableDevelopmentModeWarnings: true,
17+
},
18+
}}
19+
/>
20+
```

packages/clerk-js/src/core/resources/DisplayConfig.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export class DisplayConfig extends BaseResource implements DisplayConfigResource
4141
afterLeaveOrganizationUrl!: string;
4242
afterCreateOrganizationUrl!: string;
4343
googleOneTapClientId?: string;
44+
showDevModeWarning!: boolean;
4445

4546
public constructor(data: DisplayConfigJSON) {
4647
super();
@@ -80,6 +81,7 @@ export class DisplayConfig extends BaseResource implements DisplayConfigResource
8081
this.afterLeaveOrganizationUrl = data.after_leave_organization_url;
8182
this.afterCreateOrganizationUrl = data.after_create_organization_url;
8283
this.googleOneTapClientId = data.google_one_tap_client_id;
84+
this.showDevModeWarning = data.show_devmode_warning;
8385
return this;
8486
}
8587
}

packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationPage.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,23 @@ import { useClerk } from '@clerk/shared/react';
33
import { useCreateOrganizationContext } from '../../contexts';
44
import { localizationKeys } from '../../customizables';
55
import { Card, useCardState, withCardStateProvider } from '../../elements';
6+
import { useDevMode } from '../../hooks/useDevMode';
67
import { CreateOrganizationForm } from './CreateOrganizationForm';
78

89
export const CreateOrganizationPage = withCardStateProvider(() => {
910
const { closeCreateOrganization } = useClerk();
1011

1112
const { mode, navigateAfterCreateOrganization, skipInvitationScreen } = useCreateOrganizationContext();
1213
const card = useCardState();
14+
const { showDevModeNotice } = useDevMode();
1315

1416
return (
1517
<Card.Root sx={t => ({ width: t.sizes.$108 })}>
16-
<Card.Content sx={t => ({ padding: `${t.space.$4} ${t.space.$5} ${t.space.$6}` })}>
18+
<Card.Content
19+
sx={t => ({
20+
padding: `${t.space.$4} ${t.space.$5} ${showDevModeNotice ? t.space.$12 : t.space.$6}`,
21+
})}
22+
>
1723
<Card.Alert>{card.error}</Card.Alert>
1824
<CreateOrganizationForm
1925
skipInvitationScreen={skipInvitationScreen}

packages/clerk-js/src/ui/customizables/elementDescriptors.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export const APPEARANCE_KEYS = containsAllElementsConfigKeys([
2424
'cardBox',
2525
'card',
2626
'footerItem',
27+
'popoverBox',
2728

2829
'actionCard',
2930

packages/clerk-js/src/ui/customizables/parseAppearance.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const defaultLayout: ParsedLayout = {
4343
termsPageUrl: '',
4444
shimmer: true,
4545
animations: true,
46+
unsafe_disableDevelopmentModeWarnings: false,
4647
};
4748

4849
/**

packages/clerk-js/src/ui/elements/Card/CardClerkAndPagesTag.tsx

Lines changed: 71 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,91 @@
11
import React from 'react';
22

33
import { useEnvironment } from '../../contexts';
4-
import { Flex, Icon, Link, Text } from '../../customizables';
4+
import { Box, Col, Flex, Icon, Link, Text } from '../../customizables';
5+
import { useDevMode } from '../../hooks/useDevMode';
56
import { LogoMark } from '../../icons';
6-
import type { PropsOfComponent } from '../../styledSystem';
7+
import type { PropsOfComponent, ThemableCssProp } from '../../styledSystem';
8+
import { DevModeNotice, DevModeOverlay } from '../DevModeNotice';
79
import { Card } from '.';
810

911
export const CardClerkAndPagesTag = React.memo(
10-
React.forwardRef<HTMLDivElement, PropsOfComponent<typeof Flex> & { withFooterPages?: boolean }>((props, ref) => {
11-
const { sx, withFooterPages = false, ...rest } = props;
12-
const { branded } = useEnvironment().displayConfig;
12+
React.forwardRef<
13+
HTMLDivElement,
14+
PropsOfComponent<typeof Flex> & {
15+
withFooterPages?: boolean;
16+
devModeNoticeSx?: ThemableCssProp;
17+
outerSx?: ThemableCssProp;
18+
withDevOverlay?: boolean;
19+
}
20+
>((props, ref) => {
21+
const { sx, outerSx, withFooterPages = false, withDevOverlay = false, devModeNoticeSx, ...rest } = props;
22+
const { displayConfig } = useEnvironment();
23+
const { showDevModeNotice } = useDevMode();
1324

14-
if (!(branded || withFooterPages)) {
25+
if (!(displayConfig.branded || withFooterPages) && !showDevModeNotice) {
1526
return null;
1627
}
1728

1829
return (
19-
<Flex
30+
<Box
2031
sx={[
21-
t => ({
22-
':has(div:only-child)': {
23-
justifyContent: 'center',
24-
},
25-
justifyContent: 'space-between',
32+
{
2633
width: '100%',
27-
padding: `0 ${t.space.$8}`,
28-
}),
29-
sx,
34+
position: 'relative',
35+
isolation: 'isolate',
36+
},
37+
outerSx,
3038
]}
31-
{...rest}
32-
ref={ref}
3339
>
34-
{branded && (
35-
<Flex
36-
gap={1}
37-
align='center'
38-
justify='center'
39-
sx={t => ({ color: t.colors.$colorTextSecondary })}
40-
>
41-
<>
42-
<Text variant='buttonSmall'>Secured by</Text>
43-
<LogoMarkIconLink />
44-
</>
45-
</Flex>
46-
)}
40+
{withDevOverlay && <DevModeOverlay gradient={0} />}
41+
<Col
42+
sx={t => ({
43+
gap: displayConfig.branded || withFooterPages ? t.space.$2 : 0,
44+
marginLeft: 'auto',
45+
marginRight: 'auto',
46+
width: '100%',
47+
justifyContent: 'center',
48+
alignItems: 'center',
49+
zIndex: 1,
50+
position: 'relative',
51+
})}
52+
>
53+
{(displayConfig.branded || withFooterPages) && (
54+
<Flex
55+
sx={[
56+
{
57+
':has(div:only-child)': {
58+
justifyContent: 'center',
59+
},
60+
justifyContent: 'space-between',
61+
width: '100%',
62+
},
63+
sx,
64+
]}
65+
{...rest}
66+
ref={ref}
67+
>
68+
{displayConfig.branded && (
69+
<Flex
70+
gap={1}
71+
align='center'
72+
justify='center'
73+
sx={t => ({ color: t.colors.$colorTextSecondary })}
74+
>
75+
<>
76+
<Text variant='buttonSmall'>Secured by</Text>
77+
<LogoMarkIconLink />
78+
</>
79+
</Flex>
80+
)}
81+
82+
{withFooterPages && <Card.FooterLinks />}
83+
</Flex>
84+
)}
4785

48-
{withFooterPages && <Card.FooterLinks />}
49-
</Flex>
86+
<DevModeNotice sx={devModeNoticeSx} />
87+
</Col>
88+
</Box>
5089
);
5190
}),
5291
);

packages/clerk-js/src/ui/elements/Card/CardContent.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
useLocalizations,
1111
} from '../../customizables';
1212
import { Close } from '../../icons';
13-
import { type PropsOfComponent } from '../../styledSystem';
13+
import type { PropsOfComponent } from '../../styledSystem';
1414
import { useCardState, useFlowMetadata } from '../contexts';
1515
import { IconButton } from '../IconButton';
1616
import { useUnsafeModalContext } from '../Modal';

packages/clerk-js/src/ui/elements/Card/CardFooter.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22

33
import { useEnvironment } from '../../contexts';
44
import { descriptors, Flex, Link, localizationKeys, useAppearance } from '../../customizables';
5+
import { useDevMode } from '../../hooks/useDevMode';
56
import type { InternalTheme, PropsOfComponent } from '../../styledSystem';
67
import { common, mqu } from '../../styledSystem';
78
import { colors } from '../../utils';
@@ -12,12 +13,14 @@ type CardFooterProps = PropsOfComponent<typeof Flex> & {
1213
};
1314
export const CardFooter = React.forwardRef<HTMLDivElement, CardFooterProps>((props, ref) => {
1415
const { children, isProfileFooter = false, sx, ...rest } = props;
15-
const { branded } = useEnvironment().displayConfig;
16+
const { displayConfig } = useEnvironment();
17+
const { branded } = displayConfig;
18+
const { showDevModeNotice } = useDevMode();
1619
const { helpPageUrl, privacyPageUrl, termsPageUrl } = useAppearance().parsedLayout;
1720
const sponsorOrLinksExist = !!(branded || helpPageUrl || privacyPageUrl || termsPageUrl);
1821
const showSponsorAndLinks = isProfileFooter ? branded : sponsorOrLinksExist;
1922

20-
if (!children && !showSponsorAndLinks) {
23+
if (!children && !(showSponsorAndLinks || showDevModeNotice)) {
2124
return null;
2225
}
2326

@@ -64,7 +67,13 @@ export const CardFooter = React.forwardRef<HTMLDivElement, CardFooterProps>((pro
6467
>
6568
{children}
6669

67-
{showSponsorAndLinks && <Card.ClerkAndPagesTag withFooterPages={!isProfileFooter} />}
70+
<Card.ClerkAndPagesTag
71+
withFooterPages={showSponsorAndLinks && !isProfileFooter}
72+
devModeNoticeSx={t => ({
73+
padding: t.space.$none,
74+
})}
75+
withDevOverlay
76+
/>
6877
</Flex>
6978
);
7079
});
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import type { ThemableCssProp } from 'ui/styledSystem';
2+
3+
import { Box, Text } from '../customizables';
4+
import { useDevMode } from '../hooks/useDevMode';
5+
6+
type DevModeOverlayProps = {
7+
gradient?: number;
8+
};
9+
10+
export const DevModeOverlay = (props: DevModeOverlayProps) => {
11+
const { gradient = 60 } = props;
12+
const { showDevModeNotice } = useDevMode();
13+
14+
if (!showDevModeNotice) {
15+
return null;
16+
}
17+
18+
return (
19+
<Box
20+
sx={t => ({
21+
userSelect: 'none',
22+
pointerEvents: 'none',
23+
inset: 0,
24+
position: 'absolute',
25+
background: `repeating-linear-gradient(-45deg,${t.colors.$warningAlpha100},${t.colors.$warningAlpha100} 6px,${t.colors.$warningAlpha150} 6px,${t.colors.$warningAlpha150} 12px)`,
26+
maskImage: `linear-gradient(transparent ${gradient}%, black)`,
27+
})}
28+
/>
29+
);
30+
};
31+
32+
type DevModeNoticeProps = { sx?: ThemableCssProp };
33+
export const DevModeNotice = (props: DevModeNoticeProps) => {
34+
const { sx } = props;
35+
const { showDevModeNotice } = useDevMode();
36+
37+
if (!showDevModeNotice) {
38+
return null;
39+
}
40+
41+
return (
42+
<Text
43+
sx={[
44+
t => ({
45+
color: t.colors.$warning500,
46+
fontWeight: t.fontWeights.$semibold,
47+
padding: t.space.$1x5,
48+
}),
49+
sx,
50+
]}
51+
>
52+
Development mode
53+
</Text>
54+
);
55+
};

packages/clerk-js/src/ui/elements/Navbar.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { animations, common, mqu } from '../styledSystem';
1212
import { colors } from '../utils';
1313
import { Card } from './Card';
1414
import { withFloatingTree } from './contexts';
15+
import { DevModeOverlay } from './DevModeNotice';
1516
import { Popover } from './Popover';
1617

1718
type NavbarContextValue = { isOpen: boolean; open: () => void; close: () => void };
@@ -140,6 +141,7 @@ const NavbarContainer = (
140141
},
141142
flex: `0 0 ${t.space.$57}`,
142143
width: t.sizes.$57,
144+
position: 'relative',
143145
maxWidth: t.space.$57,
144146
background: common.mergedColorsBackground(
145147
colors.setAlpha(t.colors.$colorBackground, 1),
@@ -151,6 +153,8 @@ const NavbarContainer = (
151153
justifyContent: 'space-between',
152154
})}
153155
>
156+
<DevModeOverlay />
157+
154158
<Col sx={t => ({ gap: t.space.$6, flex: `0 0 ${t.space.$60}` })}>
155159
<Col
156160
sx={t => ({
@@ -172,10 +176,9 @@ const NavbarContainer = (
172176
</Col>
173177

174178
<Card.ClerkAndPagesTag
175-
sx={theme => ({
179+
sx={{
176180
width: 'fit-content',
177-
paddingLeft: theme.space.$3,
178-
})}
181+
}}
179182
/>
180183
</Col>
181184
);

0 commit comments

Comments
 (0)