Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .changeset/mosaic-features-dir.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
2 changes: 1 addition & 1 deletion .claude/skills/mosaic/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ canonical contract for the whole design system — the `--cl-*` tokens, the
architecture" section that defines the split. Read it for the _what_; this skill
is the _how-to_.

`packages/ui/src/mosaic/user-button/` is the fullest worked example of the split
`packages/ui/src/mosaic/features/user-button/` is the fullest worked example of the split
in the repo — model, controller, view, wrapper, types, messages, and a test per
layer. Copy from it.

Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/mosaic/references/controllers.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ against a fake object instead of a mocked Clerk.

Worked examples:

- `packages/ui/src/mosaic/user-button/user-button.controller.tsx` — wraps a model
- `packages/ui/src/mosaic/user-profile/user-profile-delete-section/user-profile-delete-section.controller.ts`
- `packages/ui/src/mosaic/features/user-button/user-button.controller.tsx` — wraps a model
- `packages/ui/src/mosaic/features/user-profile/user-profile-delete-section/user-profile-delete-section.controller.ts`
— takes its one effect as a prop

See `references/mosaic-architecture.md` → "Controllers" for the layer contract.
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/mosaic/references/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Migrating a legacy component means taking logic that was fused into one file and
pulling it apart into the model / controller / view layers (see the skill
overview and `references/mosaic-architecture.md` → "Flow and data architecture").
`packages/ui/src/mosaic/user-button/` is the fullest worked example of the
`packages/ui/src/mosaic/features/user-button/` is the fullest worked example of the
finished shape.

**The core risk this workflow exists to manage:** a legacy component fuses
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/mosaic/references/models.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Mosaic flow that may import Clerk hooks or call Clerk resource methods** — the
controller (`controllers.md`) and the view (`views.md`) stay Clerk-free, which is
what makes both testable without a Clerk fixture.

Worked example: `packages/ui/src/mosaic/user-button/user-button.model.tsx`. See
Worked example: `packages/ui/src/mosaic/features/user-button/user-button.model.tsx`. See
`references/mosaic-architecture.md` → "Models" for the layer contract.

## Shape
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/mosaic/references/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ against plain props.
Tests are Vitest + React Testing Library, co-located in `__tests__/` next to the
feature and named for the layer they cover.

`packages/ui/src/mosaic/user-button/__tests__/` is the canonical set to copy from:
`packages/ui/src/mosaic/features/user-button/__tests__/` is the canonical set to copy from:

| File | Covers |
| ---------------------------------- | ----------------------------------------------------------- |
Expand Down
3 changes: 2 additions & 1 deletion packages/swingset/src/lib/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -588,10 +588,11 @@ export const registry: StoryModule[] = [
userProfileConnectedAccountsSectionModule,
userProfileWeb3WalletsSectionModule,
userProfileDeleteSectionModule,
// Reverification
reverificationModule,
// Blocks — flows assembled from components, wired by the caller's machine.
confirmationModule,
destructiveModule,
reverificationModule,
// Components
avatarModule,
badgeModule,
Expand Down
2 changes: 1 addition & 1 deletion packages/swingset/src/stories/dialog.component.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ full example is under [A profile](#a-profile):
```tsx
import { Button } from '@clerk/ui/mosaic/components/button';
import { Dialog } from '@clerk/ui/mosaic/components/dialog';
import { UserProfileView } from '@clerk/ui/mosaic/user-profile/user-profile.view';
import { UserProfileView } from '@clerk/ui/mosaic/features/user-profile/user-profile.view';

<Dialog.Root>
<Dialog.Trigger render={<Button />}>Manage account</Dialog.Trigger>
Expand Down
2 changes: 1 addition & 1 deletion packages/swingset/src/stories/dialog.component.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { createConfirmHandle, Dialog, useConfirmedClose } from '@clerk/ui/mosaic
import { Heading } from '@clerk/ui/mosaic/components/heading';
import { Input } from '@clerk/ui/mosaic/components/input';
import { Text } from '@clerk/ui/mosaic/components/text';
import { UserProfileView } from '@clerk/ui/mosaic/user-profile/user-profile.view';
import { UserProfileView } from '@clerk/ui/mosaic/features/user-profile/user-profile.view';
import React from 'react';

import type { StoryMeta } from '@/lib/types';
Expand Down
2 changes: 1 addition & 1 deletion packages/swingset/src/stories/drawer.component.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Dialog } from '@clerk/ui/mosaic/components/dialog';
import { Drawer } from '@clerk/ui/mosaic/components/drawer';
import { Heading } from '@clerk/ui/mosaic/components/heading';
import { Text } from '@clerk/ui/mosaic/components/text';
import { UserProfileView } from '@clerk/ui/mosaic/user-profile/user-profile.view';
import { UserProfileView } from '@clerk/ui/mosaic/features/user-profile/user-profile.view';

import type { StoryMeta } from '@/lib/types';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { UserProfileAccountSectionViewProps } from '@clerk/ui/mosaic/user-profile/user-profile-account-section/user-profile-account-section.view';
import type { UserProfileAddPhoneDialogProps } from '@clerk/ui/mosaic/user-profile/user-profile-account-section/user-profile-add-phone.dialog';
import type { UserProfileAccountSectionViewProps } from '@clerk/ui/mosaic/features/user-profile/user-profile-account-section/user-profile-account-section.view';
import type { UserProfileAddPhoneDialogProps } from '@clerk/ui/mosaic/features/user-profile/user-profile-account-section/user-profile-add-phone.dialog';

interface FixtureOptions {
failAt?: UserProfileAddPhoneDialogProps['step'];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { UserProfileFormError } from '@clerk/ui/mosaic/user-profile/user-profile-account-section/user-profile-account-section.types';
import { UserProfileSaveError } from '@clerk/ui/mosaic/user-profile/user-profile-account-section/user-profile-account-section.types';
import type { UserProfileEditNameValue } from '@clerk/ui/mosaic/user-profile/user-profile-account-section/user-profile-edit-name.dialog';
import type { UserProfileFormError } from '@clerk/ui/mosaic/features/user-profile/user-profile-account-section/user-profile-account-section.types';
import { UserProfileSaveError } from '@clerk/ui/mosaic/features/user-profile/user-profile-account-section/user-profile-account-section.types';
import type { UserProfileEditNameValue } from '@clerk/ui/mosaic/features/user-profile/user-profile-account-section/user-profile-edit-name.dialog';
import { useState } from 'react';

export interface UserProfileEditNameFixtureOptions {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { UserProfileFormError } from '@clerk/ui/mosaic/user-profile/user-profile-account-section/user-profile-account-section.types';
import { UserProfileSaveError } from '@clerk/ui/mosaic/user-profile/user-profile-account-section/user-profile-account-section.types';
import type { UserProfileFormError } from '@clerk/ui/mosaic/features/user-profile/user-profile-account-section/user-profile-account-section.types';
import { UserProfileSaveError } from '@clerk/ui/mosaic/features/user-profile/user-profile-account-section/user-profile-account-section.types';
import { useState } from 'react';

export interface UserProfileEditUsernameFixtureOptions {
Expand Down
13 changes: 8 additions & 5 deletions packages/swingset/src/stories/fixtures/user-profile.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import type { UserProfileViewProps } from '@clerk/ui/mosaic/user-profile/user-profile.view';
import type { UserProfileAPIKey } from '@clerk/ui/mosaic/user-profile/user-profile-api-keys-panel.view';
import type { UserProfileViewProps } from '@clerk/ui/mosaic/features/user-profile/user-profile.view';
import type { UserProfileAPIKey } from '@clerk/ui/mosaic/features/user-profile/user-profile-api-keys-panel.view';
import type {
UserProfilePaymentMethod,
UserProfileSubscription,
} from '@clerk/ui/mosaic/user-profile/user-profile-billing-panel.view';
import type { UserProfileEmail, UserProfilePhone } from '@clerk/ui/mosaic/user-profile/user-profile-profile-panel.view';
} from '@clerk/ui/mosaic/features/user-profile/user-profile-billing-panel.view';
import type {
UserProfileEmail,
UserProfilePhone,
} from '@clerk/ui/mosaic/features/user-profile/user-profile-profile-panel.view';
import type {
UserProfileDevice,
UserProfileMfaMethod,
UserProfilePasskey,
} from '@clerk/ui/mosaic/user-profile/user-profile-security-panel.view';
} from '@clerk/ui/mosaic/features/user-profile/user-profile-security-panel.view';
import { useMemo, useState } from 'react';

import { usePreviewImage } from './use-preview-image';
Expand Down
14 changes: 7 additions & 7 deletions packages/swingset/src/stories/reverification.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import { Button } from '@clerk/ui/mosaic/components/button';
import { Card } from '@clerk/ui/mosaic/components/card';
import type { ReverificationMethod, ReverificationStep } from '@clerk/ui/mosaic/features/reverification';
import { ReverificationBackupCode } from '@clerk/ui/mosaic/features/reverification/panels/reverification-backup-code';
import { ReverificationHelp } from '@clerk/ui/mosaic/features/reverification/panels/reverification-help';
import { ReverificationMethodPicker } from '@clerk/ui/mosaic/features/reverification/panels/reverification-method-picker';
import { ReverificationOTP } from '@clerk/ui/mosaic/features/reverification/panels/reverification-otp';
import { ReverificationPasskey } from '@clerk/ui/mosaic/features/reverification/panels/reverification-passkey';
import { ReverificationPassword } from '@clerk/ui/mosaic/features/reverification/panels/reverification-password';
import { otpChannelFor } from '@clerk/ui/mosaic/features/reverification/reverification.utils';
import { ReverificationView } from '@clerk/ui/mosaic/features/reverification/reverification.view';
import { ReverificationBackupCode } from '@clerk/ui/mosaic/features/reverification/steps/reverification-backup-code';
import { ReverificationHelp } from '@clerk/ui/mosaic/features/reverification/steps/reverification-help';
import { ReverificationMethodPicker } from '@clerk/ui/mosaic/features/reverification/steps/reverification-method-picker';
import { ReverificationOTP } from '@clerk/ui/mosaic/features/reverification/steps/reverification-otp';
import { ReverificationPasskey } from '@clerk/ui/mosaic/features/reverification/steps/reverification-passkey';
import { ReverificationPassword } from '@clerk/ui/mosaic/features/reverification/steps/reverification-password';
import { useRef, useState } from 'react';

import type { StoryMeta } from '@/lib/types';

export { default as __source } from './reverification.stories?raw';

export const meta: StoryMeta = {
group: 'Blocks',
group: 'Reverification',
status: 'wip',
title: 'Reverification',
source: 'packages/ui/src/mosaic/features/reverification/reverification.view.tsx',
Expand Down
4 changes: 2 additions & 2 deletions packages/swingset/src/stories/user-button.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ that would navigate (Manage, Invite, Create organization, Add account) only clos
`UserButtonView` renders trigger and popup from one prop-driven call:

```tsx
import { UserButtonView } from '@clerk/ui/mosaic/user-button/user-button.view';
import { UserButtonView } from '@clerk/ui/mosaic/features/user-button/user-button.view';

<UserButtonView
activeSession={{ sessionId: 'sess_colin', name: 'Colin', identifier: 'colin@clerk.dev' }}
Expand All @@ -61,7 +61,7 @@ import {
UserButtonRoot,
UserButtonTrigger,
UserButtonPopup,
} from '@clerk/ui/mosaic/user-button/user-button.view';
} from '@clerk/ui/mosaic/features/user-button/user-button.view';

<UserButtonRoot {...data} {...callbacks}>
<UserButtonTrigger />
Expand Down
4 changes: 2 additions & 2 deletions packages/swingset/src/stories/user-button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
type UserButtonSession,
type UserButtonSuggestion,
UserButtonView,
} from '@clerk/ui/mosaic/user-button/user-button.view';
} from '@clerk/ui/mosaic/features/user-button/user-button.view';
import { useEffect, useState } from 'react';

import type { StoryMeta } from '@/lib/types';
Expand All @@ -22,7 +22,7 @@ export const meta: StoryMeta = {
label: 'User button',
status: 'wip',
substatus: 'needs wire-up',
source: 'packages/ui/src/mosaic/user-button/user-button.view.tsx',
source: 'packages/ui/src/mosaic/features/user-button/user-button.view.tsx',
};

// Accounts wear their own photo. Only the flagship workspace carries the Clerk mark; the rest wear
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { UserProfileFormError } from '@clerk/ui/mosaic/user-profile/user-profile-account-section/user-profile-account-section.types';
import type { UserProfileFormError } from '@clerk/ui/mosaic/features/user-profile/user-profile-account-section/user-profile-account-section.types';
import type {
UserProfileEmail,
UserProfilePhone,
} from '@clerk/ui/mosaic/user-profile/user-profile-account-section/user-profile-account-section.view';
import { UserProfileAccountSectionView } from '@clerk/ui/mosaic/user-profile/user-profile-account-section/user-profile-account-section.view';
import type { UserProfileAddPhoneDialogProps } from '@clerk/ui/mosaic/user-profile/user-profile-account-section/user-profile-add-phone.dialog';
} from '@clerk/ui/mosaic/features/user-profile/user-profile-account-section/user-profile-account-section.view';
import { UserProfileAccountSectionView } from '@clerk/ui/mosaic/features/user-profile/user-profile-account-section/user-profile-account-section.view';
import type { UserProfileAddPhoneDialogProps } from '@clerk/ui/mosaic/features/user-profile/user-profile-account-section/user-profile-add-phone.dialog';
import { useState } from 'react';

import type { StoryMeta } from '@/lib/types';
Expand All @@ -22,7 +22,8 @@ export const meta: StoryMeta = {
title: 'UserProfileAccountSection',
label: 'Account',
navigation: { category: 'Sections' },
source: 'packages/ui/src/mosaic/user-profile/user-profile-account-section/user-profile-account-section.view.tsx',
source:
'packages/ui/src/mosaic/features/user-profile/user-profile-account-section/user-profile-account-section.view.tsx',
};

function AccountSection({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { UserProfileDevice } from '@clerk/ui/mosaic/user-profile/user-profile-active-devices-section.view';
import { UserProfileActiveDevicesSectionView } from '@clerk/ui/mosaic/user-profile/user-profile-active-devices-section.view';
import type { UserProfileDevice } from '@clerk/ui/mosaic/features/user-profile/user-profile-active-devices-section.view';
import { UserProfileActiveDevicesSectionView } from '@clerk/ui/mosaic/features/user-profile/user-profile-active-devices-section.view';
import { useState } from 'react';

import type { StoryMeta } from '@/lib/types';
Expand All @@ -12,7 +12,7 @@ export const meta: StoryMeta = {
title: 'UserProfileActiveDevicesSection',
label: 'Active devices',
navigation: { category: 'Sections' },
source: 'packages/ui/src/mosaic/user-profile/user-profile-active-devices-section.view.tsx',
source: 'packages/ui/src/mosaic/features/user-profile/user-profile-active-devices-section.view.tsx',
};

export function Default() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { UserProfileAPIKey } from '@clerk/ui/mosaic/user-profile/user-profile-api-keys-panel.view';
import { UserProfileApiKeysPanelView } from '@clerk/ui/mosaic/user-profile/user-profile-api-keys-panel.view';
import type { UserProfileAPIKey } from '@clerk/ui/mosaic/features/user-profile/user-profile-api-keys-panel.view';
import { UserProfileApiKeysPanelView } from '@clerk/ui/mosaic/features/user-profile/user-profile-api-keys-panel.view';
import { useMemo, useState } from 'react';

import type { StoryMeta } from '@/lib/types';
Expand All @@ -12,7 +12,7 @@ export const meta: StoryMeta = {
title: 'UserProfileApiKeysPanel',
label: 'API keys panel',
navigation: { category: 'Panels' },
source: 'packages/ui/src/mosaic/user-profile/user-profile-api-keys-panel.view.tsx',
source: 'packages/ui/src/mosaic/features/user-profile/user-profile-api-keys-panel.view.tsx',
};

const initialAPIKeys: UserProfileAPIKey[] = [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { UserProfileBillingHistoryItem } from '@clerk/ui/mosaic/user-profile/user-profile-billing-history-section.view';
import { UserProfileBillingHistorySectionView } from '@clerk/ui/mosaic/user-profile/user-profile-billing-history-section.view';
import type { UserProfileBillingHistoryItem } from '@clerk/ui/mosaic/features/user-profile/user-profile-billing-history-section.view';
import { UserProfileBillingHistorySectionView } from '@clerk/ui/mosaic/features/user-profile/user-profile-billing-history-section.view';
import { useState } from 'react';

import type { StoryMeta } from '@/lib/types';
Expand All @@ -12,7 +12,7 @@ export const meta: StoryMeta = {
title: 'UserProfileBillingHistorySection',
label: 'Billing history',
navigation: { category: 'Sections' },
source: 'packages/ui/src/mosaic/user-profile/user-profile-billing-history-section.view.tsx',
source: 'packages/ui/src/mosaic/features/user-profile/user-profile-billing-history-section.view.tsx',
};

const items: UserProfileBillingHistoryItem[] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import type {
UserProfileBillingHistoryItem,
UserProfilePaymentMethod,
UserProfileSubscription,
} from '@clerk/ui/mosaic/user-profile/user-profile-billing-panel.view';
import { UserProfileBillingPanelView } from '@clerk/ui/mosaic/user-profile/user-profile-billing-panel.view';
} from '@clerk/ui/mosaic/features/user-profile/user-profile-billing-panel.view';
import { UserProfileBillingPanelView } from '@clerk/ui/mosaic/features/user-profile/user-profile-billing-panel.view';
import { useState } from 'react';

import type { StoryMeta } from '@/lib/types';
Expand All @@ -16,7 +16,7 @@ export const meta: StoryMeta = {
title: 'UserProfileBillingPanel',
label: 'Billing panel',
navigation: { category: 'Panels' },
source: 'packages/ui/src/mosaic/user-profile/user-profile-billing-panel.view.tsx',
source: 'packages/ui/src/mosaic/features/user-profile/user-profile-billing-panel.view.tsx',
};

const initialSubscription: UserProfileSubscription = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { UserProfileConnectedAccountsSectionView } from '@clerk/ui/mosaic/user-profile/user-profile-connected-accounts-section.view';
import { UserProfileConnectedAccountsSectionView } from '@clerk/ui/mosaic/features/user-profile/user-profile-connected-accounts-section.view';

import type { StoryMeta } from '@/lib/types';

Expand All @@ -10,7 +10,7 @@ export const meta: StoryMeta = {
title: 'UserProfileConnectedAccountsSection',
label: 'Connected accounts',
navigation: { category: 'Sections' },
source: 'packages/ui/src/mosaic/user-profile/user-profile-connected-accounts-section.view.tsx',
source: 'packages/ui/src/mosaic/features/user-profile/user-profile-connected-accounts-section.view.tsx',
};

export function Default() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { UserProfileDeleteSectionView } from '@clerk/ui/mosaic/user-profile/user-profile-delete-section/user-profile-delete-section.view';
import { UserProfileDeleteSectionView } from '@clerk/ui/mosaic/features/user-profile/user-profile-delete-section/user-profile-delete-section.view';
import { useState } from 'react';

import type { StoryMeta } from '@/lib/types';
Expand All @@ -11,7 +11,8 @@ export const meta: StoryMeta = {
title: 'UserProfileDeleteSection',
label: 'Danger zone',
navigation: { category: 'Sections' },
source: 'packages/ui/src/mosaic/user-profile/user-profile-delete-section/user-profile-delete-section.view.tsx',
source:
'packages/ui/src/mosaic/features/user-profile/user-profile-delete-section/user-profile-delete-section.view.tsx',
};

// A real delete is a network round trip. Without one the button never renders its pending
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { UserProfileMfaMethod } from '@clerk/ui/mosaic/user-profile/user-profile-mfa-section.view';
import { UserProfileMfaSectionView } from '@clerk/ui/mosaic/user-profile/user-profile-mfa-section.view';
import type { UserProfileMfaMethod } from '@clerk/ui/mosaic/features/user-profile/user-profile-mfa-section.view';
import { UserProfileMfaSectionView } from '@clerk/ui/mosaic/features/user-profile/user-profile-mfa-section.view';
import { useState } from 'react';

import type { StoryMeta } from '@/lib/types';
Expand All @@ -12,7 +12,7 @@ export const meta: StoryMeta = {
title: 'UserProfileMfaSection',
label: '2-step verification',
navigation: { category: 'Sections' },
source: 'packages/ui/src/mosaic/user-profile/user-profile-mfa-section.view.tsx',
source: 'packages/ui/src/mosaic/features/user-profile/user-profile-mfa-section.view.tsx',
};

export function Default() {
Expand Down
Loading
Loading