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(