diff --git a/.changeset/rich-readers-obey.md b/.changeset/rich-readers-obey.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/rich-readers-obey.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/short-kings-mate.md b/.changeset/short-kings-mate.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/short-kings-mate.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/spicy-feet-buy.md b/.changeset/spicy-feet-buy.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/spicy-feet-buy.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/sweet-pumas-press.md b/.changeset/sweet-pumas-press.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/sweet-pumas-press.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/tricky-swans-develop.md b/.changeset/tricky-swans-develop.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/tricky-swans-develop.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/violet-birds-scream.md b/.changeset/violet-birds-scream.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/violet-birds-scream.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/packages/clerk-js/src/ui.retheme/components/SignIn/AlternativeMethods.tsx b/packages/clerk-js/src/ui.retheme/components/SignIn/AlternativeMethods.tsx index ae32166e897..94336342938 100644 --- a/packages/clerk-js/src/ui.retheme/components/SignIn/AlternativeMethods.tsx +++ b/packages/clerk-js/src/ui.retheme/components/SignIn/AlternativeMethods.tsx @@ -3,7 +3,7 @@ import React from 'react'; import type { LocalizationKey } from '../../customizables'; import { descriptors, Flex, Flow, localizationKeys, Text } from '../../customizables'; -import { ArrowBlockButton, Card, CardAlert, Footer, Header } from '../../elements'; +import { ArrowBlockButton, BackLink, Card, CardAlert, Footer, Header } from '../../elements'; import { useCardState } from '../../elements/contexts'; import { useAlternativeStrategies } from '../../hooks/useAlternativeStrategies'; import { ChatAltIcon, Email, LinkIcon, LockClosedIcon, RequestAuthIcon } from '../../icons'; @@ -37,10 +37,23 @@ const AlternativeMethodsList = (props: AlternativeMethodListProps) => { return ( - + + + {/* TODO: Add text "Don’t have any of these?" */} + {/* */} + + + + , + ]} + > {card.error} - {onBackLinkClick && } { )} + {onBackLinkClick && ( + + )} - - - diff --git a/packages/clerk-js/src/ui.retheme/components/SignIn/ResetPassword.tsx b/packages/clerk-js/src/ui.retheme/components/SignIn/ResetPassword.tsx index 8e6a6f96766..f189a36b7f5 100644 --- a/packages/clerk-js/src/ui.retheme/components/SignIn/ResetPassword.tsx +++ b/packages/clerk-js/src/ui.retheme/components/SignIn/ResetPassword.tsx @@ -96,7 +96,6 @@ export const _ResetPassword = () => { {card.error} - navigate('../')} /> { - const { onBackLinkClick, onHavingTroubleClick, onFactorSelected } = props; + const { onHavingTroubleClick, onFactorSelected } = props; const card = useCardState(); const { supportedSecondFactors } = useCoreSignIn(); @@ -41,7 +41,6 @@ const AlternativeMethodsList = (props: AlternativeMethodsProps & { onHavingTroub {card.error} - {onBackLinkClick && } {/*TODO: extract main in its own component */} diff --git a/packages/clerk-js/src/ui.retheme/components/SignIn/SignInStart.tsx b/packages/clerk-js/src/ui.retheme/components/SignIn/SignInStart.tsx index 2077f73af2f..18271f82330 100644 --- a/packages/clerk-js/src/ui.retheme/components/SignIn/SignInStart.tsx +++ b/packages/clerk-js/src/ui.retheme/components/SignIn/SignInStart.tsx @@ -291,7 +291,20 @@ export function _SignInStart(): JSX.Element { const { action, ...identifierFieldProps } = identifierField.props; return ( - + + + + + + + , + ]} + > {card.error} @@ -325,16 +338,6 @@ export function _SignInStart(): JSX.Element { ) : null} - - - - - - - ); diff --git a/packages/clerk-js/src/ui.retheme/customizables/elementDescriptors.ts b/packages/clerk-js/src/ui.retheme/customizables/elementDescriptors.ts index 5c01521544d..6fa869c8e1c 100644 --- a/packages/clerk-js/src/ui.retheme/customizables/elementDescriptors.ts +++ b/packages/clerk-js/src/ui.retheme/customizables/elementDescriptors.ts @@ -26,9 +26,6 @@ export const APPEARANCE_KEYS = containsAllElementsConfigKeys([ 'header', 'headerTitle', 'headerSubtitle', - 'headerBackRow', - 'headerBackLink', - 'headerBackIcon', 'main', @@ -39,6 +36,9 @@ export const APPEARANCE_KEYS = containsAllElementsConfigKeys([ 'footerPages', 'footerPagesLink', + 'backRow', + 'backLink', + 'socialButtons', 'socialButtonsIconButton', 'socialButtonsBlockButton', diff --git a/packages/clerk-js/src/ui.retheme/elements/BackLink.tsx b/packages/clerk-js/src/ui.retheme/elements/BackLink.tsx index f7efff4c611..211fd6385ca 100644 --- a/packages/clerk-js/src/ui.retheme/elements/BackLink.tsx +++ b/packages/clerk-js/src/ui.retheme/elements/BackLink.tsx @@ -1,31 +1,26 @@ -import { Flex, Icon, localizationKeys, Text } from '../customizables'; +import { Flex, localizationKeys, Text } from '../customizables'; import type { ElementDescriptor } from '../customizables/elementDescriptors'; -import { ArrowLeftIcon } from '../icons'; import type { PropsOfComponent } from '../styledSystem'; import { RouterLink } from './RouterLink'; type BackLinkProps = PropsOfComponent & { boxElementDescriptor?: ElementDescriptor; linkElementDescriptor?: ElementDescriptor; - iconElementDescriptor?: ElementDescriptor; }; export const BackLink = (props: BackLinkProps) => { - const { boxElementDescriptor, linkElementDescriptor, iconElementDescriptor, ...rest } = props; + const { boxElementDescriptor, linkElementDescriptor, ...rest } = props; return ( ({ marginBottom: theme.space.$2x5 })} + sx={theme => ({ margin: `${theme.space.$none} auto` })} > - diff --git a/packages/clerk-js/src/ui.retheme/elements/Card.tsx b/packages/clerk-js/src/ui.retheme/elements/Card.tsx index b441df36057..4e628cf7f58 100644 --- a/packages/clerk-js/src/ui.retheme/elements/Card.tsx +++ b/packages/clerk-js/src/ui.retheme/elements/Card.tsx @@ -12,10 +12,13 @@ import { IconButton } from './IconButton'; import { useUnsafeModalContext } from './Modal'; import { PoweredByClerkTag } from './PoweredByClerk'; -type CardProps = PropsOfComponent & React.PropsWithChildren>; +type CardProps = PropsOfComponent & + React.PropsWithChildren<{ + footerItems?: React.ReactNode[]; + }>; export const Card = React.forwardRef((props, ref) => { - const { sx, children, ...rest } = props; + const { sx, children, footerItems, ...rest } = props; const appearance = useAppearance(); const flowMetadata = useFlowMetadata(); const { branded } = useEnvironment().displayConfig; @@ -49,8 +52,7 @@ export const Card = React.forwardRef((props, ref) => '0px 0px 2px 0px rgba(0, 0, 0, 0.08), 0px 1px 2px 0px rgba(25, 28, 33, 0.06), 0px 0px 0px 1px rgba(25, 28, 33, 0.04)', maxWidth: `calc(100vw - ${t.sizes.$20})`, width: t.sizes.$100, - borderRadius: t.radii.$lg, - textAlign: 'center', + borderRadius: `${t.radii.$card} ${t.radii.$card} ${t.radii.$lg} ${t.radii.$lg}`, }), sx, ]} @@ -60,6 +62,9 @@ export const Card = React.forwardRef((props, ref) => {children} + {footerItems?.map((item, index) => ( + {item} + ))} {branded && ( @@ -132,15 +137,12 @@ export const BaseCard = React.forwardRef((props, /> } sx={t => ({ + color: t.colors.$colorTextTertiary, zIndex: t.zIndices.$modal, - opacity: t.opacity.$inactive, - ':hover': { - opacity: 0.8, - }, position: 'absolute', - top: t.space.$3, + top: t.space.$none, + right: t.space.$none, padding: t.space.$3, - right: t.space.$3, })} /> )} @@ -158,10 +160,14 @@ export const CardFooter = React.forwardRef((pro justify='center' elementDescriptor={descriptors.cardFooter} sx={t => ({ - padding: t.space.$2, + '>:first-of-type': { + padding: `${t.space.$6} ${t.space.$2} ${t.space.$4} ${t.space.$2}`, + marginTop: `-${t.space.$2}`, + }, '>:not(:first-of-type)': { + padding: `${t.space.$4} ${t.space.$2}`, borderTop: t.borders.$normal, - borderColor: t.colors.$blackAlpha300, + borderColor: t.colors.$blackAlpha100, }, })} {...props} @@ -184,7 +190,7 @@ export const CardFooterItem = React.forwardRef ({ position: 'relative', width: '100%', - borderRadius: `0 0 ${t.radii.$xl} ${t.radii.$xl}`, + backgroundColor: t.colors.$blackAlpha200, }), ]} {...rest} diff --git a/packages/clerk-js/src/ui.retheme/elements/CodeControl.tsx b/packages/clerk-js/src/ui.retheme/elements/CodeControl.tsx index 32733bbbafd..faf76f48157 100644 --- a/packages/clerk-js/src/ui.retheme/elements/CodeControl.tsx +++ b/packages/clerk-js/src/ui.retheme/elements/CodeControl.tsx @@ -3,7 +3,7 @@ import type { PropsWithChildren } from 'react'; import React, { useCallback } from 'react'; import type { LocalizationKey } from '../customizables'; -import { descriptors, Flex, Input, Spinner, Text } from '../customizables'; +import { descriptors, Flex, Input, Spinner } from '../customizables'; import { useCardState } from '../elements/contexts'; import { useLoadingStatus } from '../hooks'; import type { PropsOfComponent } from '../styledSystem'; @@ -34,6 +34,7 @@ type UseFieldOTP = (params: { isLoading: boolean; otpControl: ReturnType; onResendCode: React.MouseEventHandler | undefined; + onFakeContinue: () => void; }; export const useFieldOTP: UseFieldOTP = params => { @@ -68,6 +69,11 @@ export const useFieldOTP: UseFieldOTP = params => { paramsOnCodeEntryFinished(code, resolve, reject); }); + const onFakeContinue = () => { + codeControlState.setError(undefined); + paramsOnCodeEntryFinished('', resolve, reject); + }; + const onResendCode = useCallback>( e => { codeControl.reset(); @@ -80,6 +86,7 @@ export const useFieldOTP: UseFieldOTP = params => { isLoading: status.isLoading, otpControl: codeControl, onResendCode: paramsOnResendCodeClicked ? onResendCode : undefined, + onFakeContinue, }; }; @@ -128,28 +135,6 @@ export const OTPRoot = ({ children, ...props }: PropsWithChildren return {children}; }; -export const OTPInputLabel = () => { - const { label } = useOTPInputContext(); - return ( - - ); -}; - -export const OTPInputDescription = () => { - const { description } = useOTPInputContext(); - return ( - - ); -}; - export const OTPResendButton = () => { const { resendButton, onResendCode, isLoading, otpControl } = useOTPInputContext(); @@ -164,7 +149,6 @@ export const OTPResendButton = () => { startDisabled isDisabled={otpControl.otpInputProps.feedbackType === 'success' || isLoading} showCounter={otpControl.otpInputProps.feedbackType !== 'success'} - sx={theme => ({ marginTop: theme.space.$6 })} localizationKey={resendButton} /> ); @@ -341,17 +325,13 @@ const SingleCharInput = React.forwardRef< ...common.textVariants(theme).h2, padding: `${theme.space.$0x5} 0`, boxSizing: 'content-box', - minWidth: '1ch', - maxWidth: theme.sizes.$7, - borderRadius: theme.radii.$none, + height: theme.space.$10, + width: theme.space.$10, + borderRadius: theme.radii.$md, border: 'none', - borderBottom: theme.borders.$heavy, ...(isSuccessfullyFilled ? { borderColor: theme.colors.$success500 } : common.borderColor(theme, props)), backgroundColor: 'unset', - '&:focus': { - boxShadow: 'none', - borderColor: theme.colors.$primary500, - }, + '&:focus': {}, })} {...rest} /> diff --git a/packages/clerk-js/src/ui.retheme/elements/Divider.tsx b/packages/clerk-js/src/ui.retheme/elements/Divider.tsx index 22f482e6e0d..876c06d6549 100644 --- a/packages/clerk-js/src/ui.retheme/elements/Divider.tsx +++ b/packages/clerk-js/src/ui.retheme/elements/Divider.tsx @@ -28,7 +28,7 @@ const DividerLine = () => { sx={t => ({ flex: '1', height: '1px', - backgroundColor: t.colors.$blackAlpha300, + backgroundColor: t.colors.$blackAlpha200, })} /> ); diff --git a/packages/clerk-js/src/ui.retheme/elements/ErrorCard.tsx b/packages/clerk-js/src/ui.retheme/elements/ErrorCard.tsx index e9758ebaf37..6e9956239f1 100644 --- a/packages/clerk-js/src/ui.retheme/elements/ErrorCard.tsx +++ b/packages/clerk-js/src/ui.retheme/elements/ErrorCard.tsx @@ -19,7 +19,6 @@ type ErrorCardProps = { }; export const ErrorCard = (props: ErrorCardProps) => { - const { onBackLinkClick } = props; const card = useCardState(); const supportEmail = useSupportEmail(); @@ -32,7 +31,6 @@ export const ErrorCard = (props: ErrorCardProps) => { {card.error} - {onBackLinkClick && } {props.cardSubtitle && } diff --git a/packages/clerk-js/src/ui.retheme/elements/FieldControl.tsx b/packages/clerk-js/src/ui.retheme/elements/FieldControl.tsx index 907f046402c..aa380cc0bdd 100644 --- a/packages/clerk-js/src/ui.retheme/elements/FieldControl.tsx +++ b/packages/clerk-js/src/ui.retheme/elements/FieldControl.tsx @@ -17,7 +17,7 @@ import { import { FormFieldContextProvider, sanitizeInputProps, useFormField } from '../primitives/hooks'; import type { PropsOfComponent } from '../styledSystem'; import type { useFormControl as useFormControlUtil } from '../utils'; -import { OTPCodeControl, OTPInputDescription, OTPInputLabel, OTPResendButton, OTPRoot } from './CodeControl'; +import { OTPCodeControl, OTPResendButton, OTPRoot } from './CodeControl'; import { useCardState } from './contexts'; import type { FormFeedbackProps } from './FormControl'; import { FormFeedback } from './FormControl'; @@ -298,8 +298,6 @@ export const Field = { LabelIcon: FieldLabelIcon, Feedback: FieldFeedback, OTPRoot, - OTPInputLabel, - OTPInputDescription, OTPCodeControl, OTPResendButton, }; diff --git a/packages/clerk-js/src/ui.retheme/elements/Footer.tsx b/packages/clerk-js/src/ui.retheme/elements/Footer.tsx index e71c39a1f08..b2996ebf801 100644 --- a/packages/clerk-js/src/ui.retheme/elements/Footer.tsx +++ b/packages/clerk-js/src/ui.retheme/elements/Footer.tsx @@ -13,6 +13,13 @@ const FooterRoot = (props: React.PropsWithChildren): JSX.Element => { {...props} justify='between' align='center' + sx={{ + '&:empty': { + // Remove the element from the DOM if `Footer.Links` is the only child and is `null`, + // causing this element to be empty, creating an unwanted spacing + display: 'none', + }, + }} /> ); }; @@ -28,6 +35,9 @@ const FooterAction = (props: FooterActionProps): JSX.Element => { elementId={descriptors.footerAction.setId(elementId)} {...rest} gap={1} + sx={t => ({ + margin: `${t.space.$none} auto`, + })} /> ); }; @@ -49,7 +59,12 @@ const FooterActionLink = (props: PropsOfComponent): JSX.Eleme ({ + // TODO: Make the color theme-aware once we have dark mode colors + color: t.colors.$primary700, + fontWeight: t.fontWeights.$medium, + })} /> ); }; @@ -64,9 +79,11 @@ const FooterLink = (props: PropsOfComponent): JSX.Element => { ); }; -const FooterLinks = React.memo((): JSX.Element => { +const FooterLinks = React.memo((): JSX.Element | null => { const { helpPageUrl, privacyPageUrl, termsPageUrl } = useAppearance().parsedLayout; + if (!helpPageUrl && !privacyPageUrl && !termsPageUrl) return null; + return ( ) => {