Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
bbd86e6
docs: add design spec for 16 new components
fcollonval Apr 9, 2026
de91917
feat(tokens): add success/warning/info colors and sidebar dimension t…
fcollonval Apr 9, 2026
68d40dd
chore(registry): add react-resizable-panels dependency
fcollonval Apr 9, 2026
0dfabd5
feat(registry): add separator component
fcollonval Apr 9, 2026
e078e8f
feat(registry): add skeleton component
fcollonval Apr 9, 2026
8e9393d
feat(registry): add scroll-area component
fcollonval Apr 9, 2026
c45d1f8
feat(registry): add table component
fcollonval Apr 9, 2026
d10df4d
feat(registry): add button-group component
fcollonval Apr 9, 2026
2a0d07c
feat(registry): add input-group component
fcollonval Apr 9, 2026
f80ec9c
feat(registry): add popover component
fcollonval Apr 9, 2026
a3ab354
feat(registry): add slider component
fcollonval Apr 9, 2026
5cd17b9
feat(registry): add collapsible component
fcollonval Apr 9, 2026
68a42e4
feat(registry): add accordion component
fcollonval Apr 9, 2026
4af767d
feat(registry): add alert-dialog component
fcollonval Apr 9, 2026
5d97fb8
feat(registry): add sheet component
fcollonval Apr 9, 2026
3546bef
feat(registry): add resizable component
fcollonval Apr 9, 2026
0e46e8d
feat(registry): add toast component
fcollonval Apr 9, 2026
840ee20
feat(registry): add field component
fcollonval Apr 9, 2026
ca070c6
feat(registry): add sidebar component
fcollonval Apr 10, 2026
876a32e
feat(registry): export all new components from index
fcollonval Apr 10, 2026
05833b5
docs: add stories for separator, skeleton, scroll-area, table, button…
fcollonval Apr 10, 2026
b0743c8
docs: add stories for popover, slider, collapsible, accordion, alert-…
fcollonval Apr 10, 2026
373e9e1
docs: add stories for field and sidebar
fcollonval Apr 10, 2026
0602e08
fix: address lint/type issues in new components
fcollonval Apr 10, 2026
67191fd
Add implementation plan
fcollonval Apr 10, 2026
7c1eb37
Fix CI
fcollonval Apr 10, 2026
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: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- name: Install Playwright Browsers
run: npx playwright install --with-deps chromium

- run: npm run typecheck
- run: npm run lint
- run: npm run build
- run: npm run typecheck
- run: npm run test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ storybook-static/
packages/registry/registry/

*storybook.log
.claude/scheduled_tasks.lock
1 change: 1 addition & 0 deletions apps/docs/.storybook/globals.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module "*.css" {}
60 changes: 60 additions & 0 deletions apps/docs/src/stories/Accordion.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import type { Meta, StoryObj } from "@storybook/react";
import {
Accordion,
AccordionItem,
AccordionTrigger,
AccordionContent,
} from "@webscit/registry";

const meta = {
title: "Components/Accordion",
component: Accordion,
tags: ["autodocs"],
} satisfies Meta<typeof Accordion>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
render: () => (
<Accordion style={{ width: "400px" }}>
<AccordionItem value="item-1">
<AccordionTrigger>Is it accessible?</AccordionTrigger>
<AccordionContent>
<div>Yes. It adheres to the WAI-ARIA design pattern.</div>
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-2">
<AccordionTrigger>Is it styled?</AccordionTrigger>
<AccordionContent>
<div>Yes. It comes with default styles using CSS scoping.</div>
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-3">
<AccordionTrigger>Is it animated?</AccordionTrigger>
<AccordionContent>
<div>Yes. It uses CSS transitions for smooth expand/collapse.</div>
</AccordionContent>
</AccordionItem>
</Accordion>
),
};

export const Playground: Story = {
render: () => (
<Accordion style={{ width: "400px" }}>
<AccordionItem value="a">
<AccordionTrigger>Section A</AccordionTrigger>
<AccordionContent>
<div>Content for section A.</div>
</AccordionContent>
</AccordionItem>
<AccordionItem value="b">
<AccordionTrigger>Section B</AccordionTrigger>
<AccordionContent>
<div>Content for section B.</div>
</AccordionContent>
</AccordionItem>
</Accordion>
),
};
49 changes: 49 additions & 0 deletions apps/docs/src/stories/AlertDialog.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { Meta, StoryObj } from "@storybook/react";
import {
AlertDialog,
AlertDialogTrigger,
AlertDialogContent,
AlertDialogHeader,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogAction,
AlertDialogCancel,
Button,
} from "@webscit/registry";

const meta = {
title: "Components/AlertDialog",
component: AlertDialog,
tags: ["autodocs"],
} satisfies Meta<typeof AlertDialog>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
render: () => (
<AlertDialog>
<AlertDialogTrigger>
<Button variant="destructive">Delete Account</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This will permanently delete your
account and remove your data from our servers.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>
<Button variant="outline">Cancel</Button>
</AlertDialogCancel>
<AlertDialogAction>
<Button variant="destructive">Continue</Button>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
),
};
48 changes: 48 additions & 0 deletions apps/docs/src/stories/ButtonGroup.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type { Meta, StoryObj } from "@storybook/react";
import { ButtonGroup, Button } from "@webscit/registry";

const meta = {
title: "Components/ButtonGroup",
component: ButtonGroup,
tags: ["autodocs"],
argTypes: {
orientation: {
control: "select",
options: ["horizontal", "vertical"],
},
},
} satisfies Meta<typeof ButtonGroup>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
render: () => (
<ButtonGroup>
<Button variant="outline">Left</Button>
<Button variant="outline">Center</Button>
<Button variant="outline">Right</Button>
</ButtonGroup>
),
};

export const Vertical: Story = {
render: () => (
<ButtonGroup orientation="vertical">
<Button variant="outline">Top</Button>
<Button variant="outline">Middle</Button>
<Button variant="outline">Bottom</Button>
</ButtonGroup>
),
};

export const Playground: Story = {
args: { orientation: "horizontal" },
render: (args) => (
<ButtonGroup {...args}>
<Button variant="outline">A</Button>
<Button variant="outline">B</Button>
<Button variant="outline">C</Button>
</ButtonGroup>
),
};
46 changes: 46 additions & 0 deletions apps/docs/src/stories/Collapsible.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { Meta, StoryObj } from "@storybook/react";
import {
Collapsible,
CollapsibleTrigger,
CollapsibleContent,
Button,
} from "@webscit/registry";

const meta = {
title: "Components/Collapsible",
component: Collapsible,
tags: ["autodocs"],
} satisfies Meta<typeof Collapsible>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
render: () => (
<Collapsible style={{ width: "350px" }}>
<CollapsibleTrigger>
<Button variant="ghost">Toggle content</Button>
</CollapsibleTrigger>
<CollapsibleContent>
<div style={{ padding: "8px", border: "1px solid var(--sct-color-border)", borderRadius: "var(--sct-radius-md)", marginTop: "8px" }}>
This content can be collapsed and expanded.
</div>
</CollapsibleContent>
</Collapsible>
),
};

export const DefaultOpen: Story = {
render: () => (
<Collapsible defaultOpen style={{ width: "350px" }}>
<CollapsibleTrigger>
<Button variant="ghost">Toggle content</Button>
</CollapsibleTrigger>
<CollapsibleContent>
<div style={{ padding: "8px", border: "1px solid var(--sct-color-border)", borderRadius: "var(--sct-radius-md)", marginTop: "8px" }}>
This starts expanded.
</div>
</CollapsibleContent>
</Collapsible>
),
};
65 changes: 65 additions & 0 deletions apps/docs/src/stories/Field.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import type { Meta, StoryObj } from "@storybook/react";
import {
Field,
FieldLabel,
FieldDescription,
FieldError,
FieldSet,
FieldLegend,
FieldGroup,
FieldSeparator,
Input,
} from "@webscit/registry";

const meta = {
title: "Components/Field",
component: Field,
tags: ["autodocs"],
} satisfies Meta<typeof Field>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
render: () => (
<Field style={{ width: "350px" }}>
<FieldLabel>Email</FieldLabel>
<Input type="email" placeholder="you@example.com" />
<FieldDescription>We will never share your email.</FieldDescription>
</Field>
),
};

export const WithError: Story = {
render: () => (
<Field invalid style={{ width: "350px" }}>
<FieldLabel>Username</FieldLabel>
<Input placeholder="Enter username" />
<FieldError>Username is required.</FieldError>
</Field>
),
};

export const FieldSetExample: Story = {
render: () => (
<FieldSet style={{ width: "400px" }}>
<FieldLegend>Contact Information</FieldLegend>
<FieldGroup>
<Field>
<FieldLabel>First Name</FieldLabel>
<Input placeholder="John" />
</Field>
<FieldSeparator />
<Field>
<FieldLabel>Last Name</FieldLabel>
<Input placeholder="Doe" />
</Field>
<FieldSeparator />
<Field>
<FieldLabel>Email</FieldLabel>
<Input type="email" placeholder="john@example.com" />
</Field>
</FieldGroup>
</FieldSet>
),
};
39 changes: 39 additions & 0 deletions apps/docs/src/stories/InputGroup.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { Meta, StoryObj } from "@storybook/react";
import { InputGroup, InputGroupAddon, Input } from "@webscit/registry";

const meta = {
title: "Components/InputGroup",
component: InputGroup,
tags: ["autodocs"],
} satisfies Meta<typeof InputGroup>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
render: () => (
<InputGroup style={{ width: "300px" }}>
<InputGroupAddon>$</InputGroupAddon>
<Input placeholder="0.00" />
</InputGroup>
),
};

export const WithSuffix: Story = {
render: () => (
<InputGroup style={{ width: "300px" }}>
<Input placeholder="username" />
<InputGroupAddon>@example.com</InputGroupAddon>
</InputGroup>
),
};

export const BothSides: Story = {
render: () => (
<InputGroup style={{ width: "300px" }}>
<InputGroupAddon>https://</InputGroupAddon>
<Input placeholder="example.com" />
<InputGroupAddon>/path</InputGroupAddon>
</InputGroup>
),
};
49 changes: 49 additions & 0 deletions apps/docs/src/stories/Popover.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { Meta, StoryObj } from "@storybook/react";
import {
Popover,
PopoverTrigger,
PopoverContent,
PopoverClose,
Button,
} from "@webscit/registry";

const meta = {
title: "Components/Popover",
component: Popover,
tags: ["autodocs"],
} satisfies Meta<typeof Popover>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
render: () => (
<Popover>
<PopoverTrigger>
<Button variant="outline">Open popover</Button>
</PopoverTrigger>
<PopoverContent>
<p style={{ fontWeight: 600, marginBottom: "4px" }}>Dimensions</p>
<p style={{ fontSize: "12px", color: "var(--sct-color-muted-foreground)" }}>
Set the dimensions for the layer.
</p>
</PopoverContent>
</Popover>
),
};

export const WithClose: Story = {
render: () => (
<Popover>
<PopoverTrigger>
<Button>Details</Button>
</PopoverTrigger>
<PopoverContent>
<p>Some detailed information here.</p>
<PopoverClose>
<Button variant="outline" size="sm">Close</Button>
</PopoverClose>
</PopoverContent>
</Popover>
),
};
Loading
Loading