diff --git a/.changeset/hungry-clouds-return.md b/.changeset/hungry-clouds-return.md new file mode 100644 index 00000000000..baf7131b575 --- /dev/null +++ b/.changeset/hungry-clouds-return.md @@ -0,0 +1,6 @@ +--- +'@clerk/clerk-js': minor +"@clerk/types": minor +--- + +Add a development mode notice to components and also introduce `popoverBox` descriptor. diff --git a/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationPage.tsx b/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationPage.tsx index 4e6b4e6dc39..4d8c1c3f4da 100644 --- a/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationPage.tsx +++ b/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationPage.tsx @@ -1,6 +1,6 @@ import { useClerk } from '@clerk/shared/react'; -import { useCreateOrganizationContext } from '../../contexts'; +import { useCreateOrganizationContext, useEnvironment } from '../../contexts'; import { localizationKeys } from '../../customizables'; import { Card, useCardState, withCardStateProvider } from '../../elements'; import { CreateOrganizationForm } from './CreateOrganizationForm'; @@ -10,10 +10,13 @@ export const CreateOrganizationPage = withCardStateProvider(() => { const { mode, navigateAfterCreateOrganization, skipInvitationScreen } = useCreateOrganizationContext(); const card = useCardState(); + const { isDevelopmentOrStaging } = useEnvironment(); return ( ({ width: t.sizes.$108 })}> - ({ padding: `${t.space.$4} ${t.space.$5} ${t.space.$6}` })}> + ({ padding: `${t.space.$4} ${t.space.$5} ${isDevelopmentOrStaging() ? t.space.$12 : t.space.$6}` })} + > {card.error} & { withFooterPages?: boolean }>((props, ref) => { - const { sx, withFooterPages = false, ...rest } = props; - const { branded } = useEnvironment().displayConfig; + React.forwardRef< + HTMLDivElement, + PropsOfComponent & { + withFooterPages?: boolean; + devModeNoticeSx?: ThemableCssProp; + outerSx?: ThemableCssProp; + withDevOverlay?: boolean; + } + >((props, ref) => { + const { sx, outerSx, withFooterPages = false, withDevOverlay = false, devModeNoticeSx, ...rest } = props; + const { displayConfig, isDevelopmentOrStaging } = useEnvironment(); + const withDevModeNotice = isDevelopmentOrStaging(); - if (!(branded || withFooterPages)) { + if (!(displayConfig.branded || withFooterPages) && !withDevModeNotice) { return null; } return ( - ({ - ':has(div:only-child)': { - justifyContent: 'center', - }, - justifyContent: 'space-between', + { width: '100%', - padding: `0 ${t.space.$8}`, - }), - sx, + position: 'relative', + isolation: 'isolate', + }, + outerSx, ]} - {...rest} - ref={ref} > - {branded && ( - ({ color: t.colors.$colorTextSecondary })} - > - <> - Secured by - - - - )} + {withDevOverlay && } + ({ + gap: displayConfig.branded || withFooterPages ? t.space.$2 : 0, + marginLeft: 'auto', + marginRight: 'auto', + width: '100%', + justifyContent: 'center', + alignItems: 'center', + zIndex: 1, + position: 'relative', + })} + > + {(displayConfig.branded || withFooterPages) && ( + + {displayConfig.branded && ( + ({ color: t.colors.$colorTextSecondary })} + > + <> + Secured by + + + + )} + + {withFooterPages && } + + )} - {withFooterPages && } - + + + ); }), ); diff --git a/packages/clerk-js/src/ui/elements/Card/CardContent.tsx b/packages/clerk-js/src/ui/elements/Card/CardContent.tsx index bb68b89eeb9..e2aed4dac9e 100644 --- a/packages/clerk-js/src/ui/elements/Card/CardContent.tsx +++ b/packages/clerk-js/src/ui/elements/Card/CardContent.tsx @@ -10,7 +10,7 @@ import { useLocalizations, } from '../../customizables'; import { Close } from '../../icons'; -import { type PropsOfComponent } from '../../styledSystem'; +import type { PropsOfComponent } from '../../styledSystem'; import { useCardState, useFlowMetadata } from '../contexts'; import { IconButton } from '../IconButton'; import { useUnsafeModalContext } from '../Modal'; @@ -24,6 +24,7 @@ export const CardContent = React.forwardRef((p const { maintenanceMode } = useEnvironment(); const card = useCardState(); const { t } = useLocalizations(); + const { isDevelopmentOrStaging } = useEnvironment(); return ( ((p boxShadow: t.shadows.$cardContentShadow, borderRadius: t.radii.$lg, position: 'relative', - padding: `${t.space.$8} ${t.space.$10}`, + padding: `${t.space.$8} ${t.space.$10} ${isDevelopmentOrStaging() ? t.space.$12 : t.space.$8} ${t.space.$10}`, justifyContent: 'center', alignContent: 'center', }), diff --git a/packages/clerk-js/src/ui/elements/Card/CardFooter.tsx b/packages/clerk-js/src/ui/elements/Card/CardFooter.tsx index 438eb5b5ede..c457d12528e 100644 --- a/packages/clerk-js/src/ui/elements/Card/CardFooter.tsx +++ b/packages/clerk-js/src/ui/elements/Card/CardFooter.tsx @@ -12,12 +12,14 @@ type CardFooterProps = PropsOfComponent & { }; export const CardFooter = React.forwardRef((props, ref) => { const { children, isProfileFooter = false, sx, ...rest } = props; - const { branded } = useEnvironment().displayConfig; + const { displayConfig, isDevelopmentOrStaging } = useEnvironment(); + const { branded } = displayConfig; + const withDevModeNotice = isDevelopmentOrStaging(); const { helpPageUrl, privacyPageUrl, termsPageUrl } = useAppearance().parsedLayout; const sponsorOrLinksExist = !!(branded || helpPageUrl || privacyPageUrl || termsPageUrl); const showSponsorAndLinks = isProfileFooter ? branded : sponsorOrLinksExist; - if (!children && !showSponsorAndLinks) { + if (!children && !(showSponsorAndLinks || withDevModeNotice)) { return null; } @@ -64,7 +66,13 @@ export const CardFooter = React.forwardRef((pro > {children} - {showSponsorAndLinks && } + ({ + padding: t.space.$none, + })} + withDevOverlay + /> ); }); diff --git a/packages/clerk-js/src/ui/elements/DevModeNotice.tsx b/packages/clerk-js/src/ui/elements/DevModeNotice.tsx new file mode 100644 index 00000000000..4ccba3bd42b --- /dev/null +++ b/packages/clerk-js/src/ui/elements/DevModeNotice.tsx @@ -0,0 +1,55 @@ +import type { ThemableCssProp } from 'ui/styledSystem'; + +import { useEnvironment } from '../contexts'; +import { Box, Text } from '../customizables'; + +type DevModeOverlayProps = { + gradient?: number; +}; + +export const DevModeOverlay = (props: DevModeOverlayProps) => { + const { gradient = 60 } = props; + const { isDevelopmentOrStaging } = useEnvironment(); + + if (!isDevelopmentOrStaging()) { + return null; + } + + return ( + ({ + userSelect: 'none', + pointerEvents: 'none', + inset: 0, + position: 'absolute', + background: `repeating-linear-gradient(-45deg,${t.colors.$warningAlpha100},${t.colors.$warningAlpha100} 6px,${t.colors.$warningAlpha150} 6px,${t.colors.$warningAlpha150} 12px)`, + maskImage: `linear-gradient(transparent ${gradient}%, black)`, + })} + /> + ); +}; + +type DevModeNoticeProps = { sx?: ThemableCssProp }; +export const DevModeNotice = (props: DevModeNoticeProps) => { + const { sx } = props; + const { isDevelopmentOrStaging } = useEnvironment(); + + if (!isDevelopmentOrStaging()) { + return null; + } + + return ( + ({ + color: t.colors.$warning500, + fontWeight: t.fontWeights.$semibold, + padding: t.space.$1x5, + }), + sx, + ]} + > + Development mode + + ); +}; diff --git a/packages/clerk-js/src/ui/elements/Navbar.tsx b/packages/clerk-js/src/ui/elements/Navbar.tsx index 6e694305bb4..94383e5f341 100644 --- a/packages/clerk-js/src/ui/elements/Navbar.tsx +++ b/packages/clerk-js/src/ui/elements/Navbar.tsx @@ -12,6 +12,7 @@ import { animations, common, mqu } from '../styledSystem'; import { colors } from '../utils'; import { Card } from './Card'; import { withFloatingTree } from './contexts'; +import { DevModeOverlay } from './DevModeNotice'; import { Popover } from './Popover'; type NavbarContextValue = { isOpen: boolean; open: () => void; close: () => void }; @@ -140,6 +141,7 @@ const NavbarContainer = ( }, flex: `0 0 ${t.space.$57}`, width: t.sizes.$57, + position: 'relative', maxWidth: t.space.$57, background: common.mergedColorsBackground( colors.setAlpha(t.colors.$colorBackground, 1), @@ -151,6 +153,8 @@ const NavbarContainer = ( justifyContent: 'space-between', })} > + + ({ gap: t.space.$6, flex: `0 0 ${t.space.$60}` })}> ({ @@ -172,10 +176,9 @@ const NavbarContainer = ( ({ + sx={{ width: 'fit-content', - paddingLeft: theme.space.$3, - })} + }} /> ); diff --git a/packages/clerk-js/src/ui/elements/PopoverCard.tsx b/packages/clerk-js/src/ui/elements/PopoverCard.tsx index 1ccdf83a74c..d12a6f5ade9 100644 --- a/packages/clerk-js/src/ui/elements/PopoverCard.tsx +++ b/packages/clerk-js/src/ui/elements/PopoverCard.tsx @@ -1,17 +1,20 @@ import React from 'react'; import { useEnvironment } from '../contexts'; -import { Col, Flex, Flow, useAppearance } from '../customizables'; +import { Col, descriptors, Flex, Flow, useAppearance } from '../customizables'; +import type { ElementDescriptor } from '../customizables/elementDescriptors'; import type { PropsOfComponent } from '../styledSystem'; import { animations, common } from '../styledSystem'; import { colors } from '../utils'; import { Card } from '.'; const PopoverCardRoot = React.forwardRef>((props, ref) => { + const { elementDescriptor, ...rest } = props; return ( ({ width: t.sizes.$94, @@ -70,8 +73,6 @@ const PopoverCardFooter = (props: PropsOfComponent) => { ), marginTop: `-${t.space.$2}`, paddingTop: t.space.$2, - borderBottomLeftRadius: 'inherit', - borderBottomRightRadius: 'inherit', '&:empty': { padding: 0, marginTop: 0, @@ -89,12 +90,16 @@ const PopoverCardFooter = (props: PropsOfComponent) => { > {children} - {shouldShowTagOrLinks && ( - ({ padding: `${t.space.$4} ${t.space.$8}` })} - /> - )} + ({ + padding: `${t.space.$4} ${t.space.$none}`, + })} + withFooterPages={!!shouldShowTagOrLinks} + devModeNoticeSx={t => ({ + padding: t.space.$none, + })} + withDevOverlay + /> ); }; diff --git a/packages/clerk-js/src/ui/elements/index.ts b/packages/clerk-js/src/ui/elements/index.ts index 349d8d6845a..6d86e286eea 100644 --- a/packages/clerk-js/src/ui/elements/index.ts +++ b/packages/clerk-js/src/ui/elements/index.ts @@ -55,3 +55,4 @@ export * from './Card'; export * from './ProfileCard'; export * from './Gauge'; export * from './Animated'; +export * from './DevModeNotice'; diff --git a/packages/clerk-js/src/ui/polishedAppearance.ts b/packages/clerk-js/src/ui/polishedAppearance.ts index 98f027c8826..fc56872c229 100644 --- a/packages/clerk-js/src/ui/polishedAppearance.ts +++ b/packages/clerk-js/src/ui/polishedAppearance.ts @@ -164,6 +164,10 @@ export const polishedAppearance: Appearance = { borderWidth: 0, boxShadow: `${theme.shadows.$cardBoxShadow}, ${BORDER_SHADOW_LENGTH} ${theme.colors.$neutralAlpha100}`, }, + popoverBox: { + borderWidth: 0, + boxShadow: `${theme.shadows.$cardBoxShadow}, ${BORDER_SHADOW_LENGTH} ${theme.colors.$neutralAlpha100}`, + }, card: { ...cardContentStyles(theme), }, diff --git a/packages/types/src/appearance.ts b/packages/types/src/appearance.ts index d09c12a1e4d..ef1a472abe3 100644 --- a/packages/types/src/appearance.ts +++ b/packages/types/src/appearance.ts @@ -143,6 +143,7 @@ export type ElementsConfig = { cardBox: WithOptions; card: WithOptions; actionCard: WithOptions; + popoverBox: WithOptions; logoBox: WithOptions; logoImage: WithOptions;