-
Notifications
You must be signed in to change notification settings - Fork 454
feat(ui): add mosaic block/section/aio prototype layers #8838
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
alexcarpenter
wants to merge
27
commits into
main
Choose a base branch
from
carp/mosaic-block-destructive
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
a763cec
feat(ui): Introduce mosaic recipes and conditions
alexcarpenter 19f2724
resolve className
alexcarpenter ddcbced
fix(ui): use useInsertionEffect to wrap emotion styles in @layer
alexcarpenter 5d3c280
fix(swingset): wire cssLayerName and defer render until mounted
alexcarpenter 6f2b1d1
refactor(headless): stop emitting data-cl-slot from dialog parts
alexcarpenter 7187514
feat(ui): migrate mosaic Dialog to slot recipes
alexcarpenter cfdfa2c
refactor(ui): use color variant on Button and omit native color prop
alexcarpenter 96d10e8
fix(ui): remove emotion @layer insertion effect from MosaicProvider
alexcarpenter 157fec5
feat(swingset): add mosaic Dialog story with group-aware routing
alexcarpenter fb83adb
test(ui): drop @layer cssLayerName assertions for removed insertion e…
alexcarpenter 32f8997
Update mosaic-architecture.md
alexcarpenter d46e35c
Merge branch 'main' into carp/mosaic-recipes
alexcarpenter f64269d
feat(ui): add mosaic block, section, and aio prototype layers
alexcarpenter 5975b38
fix(swingset): sort imports and extract trigger component for ESLint
alexcarpenter df54c31
feat(ui): add Mosaic Delete Org section and destructive button varian…
kylemac 8bb085d
cleanup
alexcarpenter f3c3e2d
mock organization store
alexcarpenter 58e57f2
Update destructive.stories.tsx
alexcarpenter b2ef9ff
rough in skeleton
alexcarpenter 356010b
Update skeleton.tsx
alexcarpenter 4d005fe
rough in tabs
alexcarpenter 88f7d9d
extract panel
alexcarpenter 0aa335b
fix dark mode
alexcarpenter 541c4e6
chore(ui): move alien-signals to devDependencies
alexcarpenter b7f8e2c
Merge remote-tracking branch 'origin/main' into carp/mosaic-block-des…
alexcarpenter 3907704
fix(swingset): sort imports in registry after merge resolution
alexcarpenter d4ba05b
Delete .changeset/delete-org-block.md
alexcarpenter File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| --- | ||
| --- |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| 'use client'; | ||
|
|
||
| import Link from 'next/link'; | ||
|
|
||
| export interface CompositionPiece { | ||
| /** Display name of the piece (e.g. `Destructive`). */ | ||
| name: string; | ||
| /** Route to the piece's page in swingset (e.g. `/blocks/destructive`). */ | ||
| href: string; | ||
| /** Which Mosaic layer the piece lives in (e.g. `Blocks`, `Components`, `Primitives`). */ | ||
| layer: string; | ||
| } | ||
|
|
||
| // Mosaic layers, high → low. Drives the order the composition groups render in. | ||
| // Plural to match the sidebar group names. | ||
| const LAYER_ORDER = ['AIO', 'Sections', 'Blocks', 'Components', 'Primitives']; | ||
|
|
||
| function layerRank(layer: string): number { | ||
| const i = LAYER_ORDER.indexOf(layer); | ||
| return i === -1 ? LAYER_ORDER.length : i; | ||
| } | ||
|
|
||
| /** | ||
| * The linked pieces shown inside a `<Story>`'s attached "Composition" footer, sorted | ||
| * and grouped by Mosaic layer. Each piece links to its own page. | ||
| */ | ||
| export function CompositionPanel({ pieces }: { pieces: CompositionPiece[] }) { | ||
| const groups = new Map<string, CompositionPiece[]>(); | ||
| for (const piece of pieces) { | ||
| if (!groups.has(piece.layer)) { | ||
| groups.set(piece.layer, []); | ||
| } | ||
| groups.get(piece.layer)?.push(piece); | ||
| } | ||
|
|
||
| const sortedLayers = Array.from(groups.keys()).sort((a, b) => layerRank(a) - layerRank(b) || a.localeCompare(b)); | ||
|
|
||
| return ( | ||
| <div className='flex flex-col gap-4 p-3'> | ||
| {sortedLayers.map(layer => ( | ||
| <section | ||
| key={layer} | ||
| className='flex flex-col gap-2' | ||
| > | ||
| <div className='text-brand text-[10px] font-semibold uppercase tracking-widest'>{layer}</div> | ||
| {groups | ||
| .get(layer) | ||
| ?.slice() | ||
| .sort((a, b) => a.name.localeCompare(b.name)) | ||
| .map(piece => ( | ||
| <Link | ||
| key={piece.href} | ||
| href={piece.href} | ||
| className='text-muted-foreground hover:text-foreground font-mono text-xs' | ||
| > | ||
| {`<${piece.name} />`} | ||
| </Link> | ||
| ))} | ||
| </section> | ||
| ))} | ||
| </div> | ||
| ); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,30 +1,65 @@ | ||
| 'use client'; | ||
|
|
||
| import { MosaicProvider } from '@clerk/ui/mosaic/MosaicProvider'; | ||
| import { Layers2Icon } from 'lucide-react'; | ||
| import type React from 'react'; | ||
| import { useState } from 'react'; | ||
|
|
||
| import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; | ||
| import { generateKnobs, initKnobValues } from '@/lib/generateKnobs'; | ||
| import type { StoryModule } from '@/lib/types'; | ||
|
|
||
| import type { CompositionPiece } from './Composition'; | ||
| import { CompositionPanel } from './Composition'; | ||
|
|
||
| interface StoryEmbedProps { | ||
| name: string; | ||
| storyModule: StoryModule; | ||
| /** When provided, a collapsible "Composition" footer is attached to the example card. */ | ||
| composition?: CompositionPiece[]; | ||
| } | ||
|
|
||
| export function StoryEmbed({ name, storyModule }: StoryEmbedProps) { | ||
| export function StoryEmbed({ name, storyModule, composition }: StoryEmbedProps) { | ||
| const StoryComp = storyModule[name] as React.ComponentType<Record<string, unknown>>; | ||
| const [compositionOpen, setCompositionOpen] = useState(false); | ||
|
|
||
| if (!StoryComp) { | ||
| return <div className='rounded bg-red-50 p-3 text-sm text-red-500'>Story "{name}" not found</div>; | ||
| } | ||
|
|
||
| const knobs = generateKnobs(storyModule.meta); | ||
| const defaultValues = initKnobValues(knobs); | ||
|
|
||
| return ( | ||
| <div className='not-prose border-border bg-background my-4 flex min-h-20 items-center justify-center rounded-lg border p-6'> | ||
| const preview = ( | ||
| <div className='flex min-h-20 items-center justify-center p-6'> | ||
| <MosaicProvider> | ||
| <StoryComp {...defaultValues} /> | ||
| </MosaicProvider> | ||
| </div> | ||
| ); | ||
|
|
||
| if (!composition) { | ||
| return <div className='not-prose border-border bg-background my-4 rounded-lg border'>{preview}</div>; | ||
| } | ||
|
|
||
| return ( | ||
| <Collapsible | ||
| open={compositionOpen} | ||
| onOpenChange={setCompositionOpen} | ||
| className='not-prose border-border bg-background my-4 overflow-hidden rounded-lg border' | ||
| > | ||
| {preview} | ||
|
|
||
| <div className='flex items-center justify-start gap-1 border-t px-2 py-1.5'> | ||
| <CollapsibleTrigger className='text-muted-foreground hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground flex items-center gap-1 rounded px-2 py-1 text-xs'> | ||
| <Layers2Icon className='size-3' /> | ||
| Composition | ||
| </CollapsibleTrigger> | ||
| </div> | ||
|
|
||
| <CollapsibleContent className='border-t'> | ||
| <CompositionPanel pieces={composition} /> | ||
| </CollapsibleContent> | ||
| </Collapsible> | ||
| ); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import * as DeleteOrganizationStories from './delete-organization.stories'; | ||
|
|
||
| # Delete Organization | ||
|
|
||
| A section that owns the open/deleting state and wires the `Destructive` block to the delete-organization flow. | ||
|
|
||
| <Story | ||
| name='Default' | ||
| storyModule={DeleteOrganizationStories} | ||
| composition={[ | ||
| { name: 'Destructive', href: '/blocks/destructive', layer: 'Blocks' }, | ||
| { name: 'Button', href: '/components/button', layer: 'Components' }, | ||
| { name: 'Input', href: '/components/input', layer: 'Components' }, | ||
| { name: 'Dialog', href: '/components/dialog', layer: 'Components' }, | ||
| ]} | ||
| /> |
15 changes: 15 additions & 0 deletions
15
packages/swingset/src/stories/delete-organization.stories.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| /** @jsxImportSource @emotion/react */ | ||
| import { DeleteOrganization } from '@clerk/ui/mosaic/sections/delete-organization'; | ||
|
|
||
| import type { StoryMeta } from '@/lib/types'; | ||
|
|
||
| export const meta: StoryMeta = { | ||
| group: 'Sections', | ||
| title: 'DeleteOrganization', | ||
| label: 'Delete Org', | ||
| source: 'packages/ui/src/mosaic/sections/delete-organization.tsx', | ||
| }; | ||
|
|
||
| export function Default() { | ||
| return <DeleteOrganization />; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import * as DestructiveStories from './destructive.stories'; | ||
|
|
||
| # Destructive | ||
|
|
||
| A controlled block that composes a trigger button, a confirmation dialog, and a guarded input — the user must type the resource name exactly before the action is enabled. | ||
|
|
||
| <Story | ||
| name='Default' | ||
| storyModule={DestructiveStories} | ||
| /> |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
temporary til #8820 lands