diff --git a/.changeset/extend-mosaic-spacing-scale.md b/.changeset/extend-mosaic-spacing-scale.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/extend-mosaic-spacing-scale.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/user-profile-section-style-alignment.md b/.changeset/user-profile-section-style-alignment.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/user-profile-section-style-alignment.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/packages/swingset/src/stories/section.mdx b/packages/swingset/src/stories/section.mdx index 640904aedb6..c19ff9a638e 100644 --- a/packages/swingset/src/stories/section.mdx +++ b/packages/swingset/src/stories/section.mdx @@ -26,9 +26,9 @@ import { Section } from '@clerk/ui/mosaic/components/section'; ``` -`Section.Group` owns the outlined surface. Its direct `Section.Row` children own separation and may stack one or more `Section.Item` entries. Each item lays out optional media, flexible content, and trailing actions. `Section.Media` accepts `md` and `lg` sizes. +`Section.Group` owns the outlined surface. Its direct `Section.Row` children own separation and may stack one or more `Section.Item` entries. Each item lays out optional media, flexible content, and trailing actions. `Section.Media` accepts `sm`, `md`, `lg`, and `xl` sizes. -Use `Section.Items` for a nested value list beneath a row's header item. The row keeps an 8px header-to-list gap, nested items stack without gaps at a 44px minimum height, and their content receives 12px vertical padding. +Use `Section.Items` for a nested value list beneath a row's header item. The row keeps a 12px header-to-list gap, and nested items stack without gaps with 4px vertical padding. ## Examples diff --git a/packages/swingset/src/stories/section.stories.tsx b/packages/swingset/src/stories/section.stories.tsx index 44dfec684c8..6cdc9b945c8 100644 --- a/packages/swingset/src/stories/section.stories.tsx +++ b/packages/swingset/src/stories/section.stories.tsx @@ -3,6 +3,7 @@ import { Badge } from '@clerk/ui/mosaic/components/badge'; import { Button } from '@clerk/ui/mosaic/components/button'; import { Icon } from '@clerk/ui/mosaic/components/icon'; import { Section } from '@clerk/ui/mosaic/components/section'; +import * as stylex from '@stylexjs/stylex'; import type { StoryMeta } from '@/lib/types'; @@ -10,13 +11,33 @@ export { default as __source } from './section.stories?raw'; const providerIconUrl = (provider: string) => `https://img.clerk.com/static/${provider}.svg`; +const styles = stylex.create({ + providerMedia: { + backgroundColor: 'var(--cl-color-background)', + borderColor: 'light-dark(var(--cl-color-border-faded), var(--cl-color-background))', + borderRadius: 'var(--cl-radius-lg)', + borderStyle: 'solid', + borderWidth: '1px', + }, + providerIcon: { + display: 'block', + height: '20px', + width: '20px', + }, +}); + function ProviderIcon({ provider }: { provider: string }) { return ( - + + + ); } @@ -33,18 +54,27 @@ export function Default() { - - Profile picture - PNG or JPEG, Recommended size 1:1, up to 10MB. - - - + + PB + + + Profile picture + Recommend size 1:1, up to 10MB. + + + @@ -61,7 +91,7 @@ export function Default() { size='sm' variant='outline' > - Update name + Edit name @@ -79,7 +109,7 @@ export function Default() { size='sm' variant='outline' > - Update username + Edit username @@ -114,18 +144,27 @@ export function MultipleEmailAndPhoneNumbers() { - - Profile picture - PNG or JPEG, Recommended size 1:1, up to 10MB. - - - + + PB + + + Profile picture + Recommend size 1:1, up to 10MB. + + + @@ -142,7 +181,7 @@ export function MultipleEmailAndPhoneNumbers() { size='sm' variant='outline' > - Update name + Edit name @@ -160,7 +199,7 @@ export function MultipleEmailAndPhoneNumbers() { size='sm' variant='outline' > - Update username + Edit username @@ -177,12 +216,7 @@ export function MultipleEmailAndPhoneNumbers() { size='sm' variant='outline' > - Add - + Add email @@ -236,12 +270,7 @@ export function MultipleEmailAndPhoneNumbers() { size='sm' variant='outline' > - Add - + Add phone number @@ -279,9 +308,7 @@ export function ConnectedAccounts() { - - - + Google test@google.com @@ -301,9 +328,7 @@ export function ConnectedAccounts() { - - - + Apple @@ -314,6 +339,11 @@ export function ConnectedAccounts() { variant='outline' > Connect + @@ -340,7 +370,7 @@ export function Destructive() { diff --git a/packages/ui/src/mosaic/components/section/section.styles.ts b/packages/ui/src/mosaic/components/section/section.styles.ts new file mode 100644 index 00000000000..df51f9e5472 --- /dev/null +++ b/packages/ui/src/mosaic/components/section/section.styles.ts @@ -0,0 +1,117 @@ +import * as stylex from '@stylexjs/stylex'; + +import { colorVars, fontWeightVars, radiusVars, space, typeScaleVars } from '../../tokens.stylex'; +import { sectionItemsMarker } from './section.markers.stylex'; + +/* eslint-disable @stylexjs/no-lookahead-selectors -- Mosaic's supported browsers include :has(); + the marker keeps this selector scoped to Section.Items. */ +export const styles = stylex.create({ + root: { + display: 'flex', + flexDirection: 'column', + rowGap: space['2'], + width: '100%', + }, + title: { + fontWeight: fontWeightVars['--cl-font-medium'], + }, + group: { + borderColor: colorVars['--cl-color-border'], + borderRadius: radiusVars['--cl-radius-xl'], + borderStyle: 'solid', + borderWidth: '1px', + overflow: 'hidden', + backgroundColor: colorVars['--cl-color-card'], + width: '100%', + }, + row: { + marginInline: space['4'], + borderBlockStartColor: colorVars['--cl-color-border'], + borderBlockStartStyle: 'solid', + borderBlockStartWidth: { + default: '1px', + ':first-child': '0px', + }, + display: 'flex', + flexDirection: 'column', + paddingBlockEnd: { + default: space['4'], + [stylex.when.descendant('[data-nested]', sectionItemsMarker)]: space['1'], + }, + paddingBlockStart: space['4'], + rowGap: { + default: space['2'], + [stylex.when.descendant('[data-nested]', sectionItemsMarker)]: space['3'], + }, + minHeight: `calc(${space['18.5']} + 1px)`, + width: 'auto', + }, + items: { + display: 'flex', + flexDirection: 'column', + width: '100%', + }, + item: { + alignItems: 'center', + columnGap: space['3'], + display: 'flex', + flexWrap: 'nowrap', + justifyContent: 'space-between', + width: '100%', + }, + nestedItem: { + paddingBlock: space['1'], + }, + mediaBase: { + alignItems: 'center', + alignSelf: 'center', + aspectRatio: '1/1', + display: 'flex', + flexShrink: 0, + justifyContent: 'center', + }, + mediaSm: { + height: space['4'], + width: space['4'], + }, + mediaMd: { + height: space['6'], + width: space['6'], + }, + mediaLg: { + height: space['10'], + width: space['10'], + }, + mediaXl: { + height: space['12'], + width: space['12'], + }, + content: { + display: 'flex', + flexDirection: 'column', + flexGrow: 1, + justifyContent: 'center', + rowGap: space['0.5'], + minWidth: 0, + }, + label: { + color: colorVars['--cl-color-card-foreground'], + fontSize: typeScaleVars['--cl-text-sm-size'], + fontWeight: fontWeightVars['--cl-font-medium'], + lineHeight: typeScaleVars['--cl-text-sm-leading'], + }, + description: { + color: colorVars['--cl-color-neutral-faded'], + fontSize: typeScaleVars['--cl-text-sm-size'], + fontWeight: fontWeightVars['--cl-font-normal'], + lineHeight: typeScaleVars['--cl-text-sm-leading'], + textWrap: 'balance', + }, + actions: { + alignItems: 'center', + display: 'flex', + flexShrink: 0, + justifyContent: 'flex-end', + }, +}); +/* eslint-enable @stylexjs/no-lookahead-selectors */ diff --git a/packages/ui/src/mosaic/components/section/section.tsx b/packages/ui/src/mosaic/components/section/section.tsx index 601e9bddfab..944166d2a8e 100644 --- a/packages/ui/src/mosaic/components/section/section.tsx +++ b/packages/ui/src/mosaic/components/section/section.tsx @@ -5,11 +5,11 @@ import React from 'react'; import type { MosaicComponentProps } from '../../props'; import { mergeStyleProps, themeProps } from '../../props'; -import { colorVars, fontWeightVars, radiusVars, space, typeScaleVars } from '../../tokens.stylex'; import type { HeadingProps } from '../heading'; import { Heading } from '../heading'; import { reset } from '../reset.styles'; import { sectionItemsMarker } from './section.markers.stylex'; +import { styles } from './section.styles'; export type SectionRootProps = Omit, 'title'>; export type SectionTitleProps = Omit; @@ -17,123 +17,18 @@ export type SectionGroupProps = MosaicComponentProps<'div'>; export type SectionRowProps = MosaicComponentProps<'div'>; export type SectionItemsProps = MosaicComponentProps<'div'>; export type SectionItemProps = MosaicComponentProps<'div'>; -export type SectionMediaSize = 'sm' | 'md' | 'lg'; +export type SectionMediaSize = 'sm' | 'md' | 'lg' | 'xl'; export type SectionMediaProps = MosaicComponentProps<'div'> & { size?: SectionMediaSize }; export type SectionContentProps = MosaicComponentProps<'div'>; export type SectionLabelProps = MosaicComponentProps<'div'>; export type SectionDescriptionProps = MosaicComponentProps<'div'>; export type SectionActionsProps = MosaicComponentProps<'div'>; -/* eslint-disable @stylexjs/no-lookahead-selectors -- Mosaic's supported browsers include :has(); - the marker keeps this selector scoped to Section.Items. */ -const styles = stylex.create({ - root: { - display: 'flex', - flexDirection: 'column', - rowGap: space['2'], - width: '100%', - }, - group: { - borderColor: colorVars['--cl-color-border'], - borderRadius: radiusVars['--cl-radius-xl'], - borderStyle: 'solid', - borderWidth: '1px', - overflow: 'hidden', - backgroundColor: colorVars['--cl-color-background'], - width: '100%', - }, - row: { - marginInline: space['4'], - borderBlockStartColor: colorVars['--cl-color-border'], - borderBlockStartStyle: 'solid', - borderBlockStartWidth: { - default: '1px', - ':first-child': '0px', - }, - display: 'flex', - flexDirection: 'column', - paddingBlockEnd: { - default: space['4'], - [stylex.when.descendant('[data-nested]', sectionItemsMarker)]: space['1'], - }, - paddingBlockStart: space['4'], - rowGap: space['2'], - width: 'auto', - }, - items: { - display: 'flex', - flexDirection: 'column', - width: '100%', - }, - item: { - alignItems: 'center', - columnGap: space['3'], - display: 'flex', - flexWrap: 'nowrap', - justifyContent: 'space-between', - width: '100%', - }, - nestedItem: { - minHeight: space['11'], - }, - mediaBase: { - alignItems: 'center', - alignSelf: 'center', - aspectRatio: '1/1', - display: 'flex', - flexShrink: 0, - justifyContent: 'center', - }, - mediaSm: { - height: space['4'], - width: space['4'], - }, - mediaMd: { - height: space['6'], - width: space['6'], - }, - mediaLg: { - height: space['8'], - width: space['8'], - }, - content: { - display: 'flex', - flexDirection: 'column', - flexGrow: 1, - justifyContent: 'center', - rowGap: space['0.5'], - minWidth: 0, - }, - nestedContent: { - paddingBlock: space['3'], - }, - label: { - color: colorVars['--cl-color-card-foreground'], - fontSize: typeScaleVars['--cl-text-sm-size'], - fontWeight: fontWeightVars['--cl-font-medium'], - lineHeight: typeScaleVars['--cl-text-sm-leading'], - }, - description: { - color: colorVars['--cl-color-neutral-faded'], - fontSize: typeScaleVars['--cl-text-sm-size'], - fontWeight: fontWeightVars['--cl-font-medium'], - lineHeight: typeScaleVars['--cl-text-sm-leading'], - textWrap: 'balance', - }, - actions: { - alignItems: 'center', - display: 'flex', - flexShrink: 0, - justifyContent: 'flex-end', - marginInlineStart: space['3'], - }, -}); -/* eslint-enable @stylexjs/no-lookahead-selectors */ - const mediaSizes = { sm: styles.mediaSm, md: styles.mediaMd, lg: styles.mediaLg, + xl: styles.mediaXl, }; const SectionTitleContext = React.createContext> | null>(null); @@ -183,7 +78,7 @@ const Title = React.forwardRef(function S id={id} render={render ?? (props =>

)} size='sm' - {...mergeStyleProps(themeProps('section-title'), className, style)} + {...mergeStyleProps(themeProps('section-title'), stylex.props(styles.title), className, style)} {...rest} /> ); @@ -296,7 +191,7 @@ const Content = React.forwardRef(function S props: { ...mergeStyleProps( themeProps('section-content', { nested }), - stylex.props(reset.base, styles.content, nested && styles.nestedContent), + stylex.props(reset.base, styles.content), className, style, ), diff --git a/packages/ui/src/mosaic/icons/registry.tsx b/packages/ui/src/mosaic/icons/registry.tsx index 26a28cda818..a652c87c706 100644 --- a/packages/ui/src/mosaic/icons/registry.tsx +++ b/packages/ui/src/mosaic/icons/registry.tsx @@ -94,6 +94,13 @@ const Plus = glyph( />, ); +const ArrowRightTop = glyph( + , +); + const Pen = glyph(