feat: add sheet component and docs qa baseline

This commit is contained in:
2026-03-19 18:46:20 +08:00
parent 71ebb010b9
commit f318f94c9a
28 changed files with 1799 additions and 91 deletions
@@ -16,24 +16,15 @@ import {
} from "@ai-ui/ui";
import type { Meta, StoryObj } from "@storybook/react";
const meta = {
title: "Components/DropdownMenu",
component: DropdownMenu,
parameters: {
layout: "centered"
},
tags: ["autodocs"]
} satisfies Meta<typeof DropdownMenu>;
type ReleaseMenuProps = {
triggerLabel?: string;
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Playground: Story = {
render: () => (
function ReleaseMenu({ triggerLabel = "Open menu" }: ReleaseMenuProps) {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="secondary">Open menu</Button>
<Button variant="secondary">{triggerLabel}</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>Launch actions</DropdownMenuLabel>
@@ -45,6 +36,10 @@ export const Playground: Story = {
Share preview
<DropdownMenuShortcut>S</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem disabled>
Retry checks
<DropdownMenuShortcut>R</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuCheckboxItem checked>Notify stakeholders</DropdownMenuCheckboxItem>
<DropdownMenuSeparator />
@@ -62,5 +57,110 @@ export const Playground: Story = {
</DropdownMenuSub>
</DropdownMenuContent>
</DropdownMenu>
);
}
const meta = {
title: "Components/DropdownMenu",
component: DropdownMenu,
parameters: {
docs: {
description: {
component:
"DropdownMenu is the compact action surface for contextual commands, quick toggles, and short decision trees. It supports labels, separators, nested submenus, checkbox and radio items, destructive emphasis, and keyboard-first navigation without introducing a separate API style."
}
},
layout: "centered"
},
tags: ["autodocs"]
} satisfies Meta<typeof DropdownMenu>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Playground: Story = {
render: () => <ReleaseMenu />
};
export const States: Story = {
parameters: {
docs: {
description: {
story:
"Open the menu to inspect the checked checkbox item, the selected radio item, a disabled action, the inset submenu trigger, and the destructive nested action."
}
}
},
render: () => (
<div className="grid w-[680px] gap-3 sm:grid-cols-2">
<ReleaseMenu triggerLabel="Review lane menu" />
<ReleaseMenu triggerLabel="Launch action menu" />
</div>
)
};
export const Anatomy: Story = {
render: () => (
<div className="w-[720px] rounded-[var(--radius-lg)] border border-[var(--color-border)] bg-[var(--color-card)] p-6 text-[var(--color-foreground)] shadow-[var(--shadow-sm)]">
<div className="space-y-3">
<p className="text-xs uppercase tracking-[var(--tracking-caps)] text-[var(--color-muted-foreground)]">
Dropdown menu anatomy
</p>
<ReleaseMenu triggerLabel="Inspect menu structure" />
<div className="grid gap-3 text-sm leading-6 text-[var(--color-muted-foreground)]">
<p>
<code className="text-[var(--color-foreground)]">data-slot="content"</code> frames
the floating panel and exposes sizing for denser menus.
</p>
<p>
<code className="text-[var(--color-foreground)]">data-slot="item"</code>,{" "}
<code className="text-[var(--color-foreground)]">data-slot="trigger"</code>, and{" "}
<code className="text-[var(--color-foreground)]">data-slot="shortcut"</code> map the
action rows, nested trigger, and keyboard hint.
</p>
<p>
<code className="text-[var(--color-foreground)]">data-slot="label"</code>,{" "}
<code className="text-[var(--color-foreground)]">data-slot="separator"</code>, and{" "}
<code className="text-[var(--color-foreground)]">data-slot="icon"</code> support
grouping, dividers, and selection markers.
</p>
</div>
</div>
</div>
)
};
export const Accessibility: Story = {
parameters: {
docs: {
description: {
story:
"Dropdown menus are optimized for keyboard and pointer parity. Focus moves with arrow keys, typeahead remains available through Radix semantics, and destructive options should stay visually distinct from neutral commands."
}
}
},
render: () => (
<div className="grid w-[760px] gap-4 lg:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)]">
<article className="rounded-[var(--radius-lg)] border border-[var(--color-border)] bg-[var(--color-card)] p-6 shadow-[var(--shadow-sm)]">
<h3 className="text-lg font-semibold tracking-[var(--tracking-tight)]">
Keyboard guidance
</h3>
<div className="mt-4 grid gap-3 text-sm leading-6 text-[var(--color-muted-foreground)]">
<p>Use labels and separators to group commands into short scannable clusters.</p>
<p>
Keep checkbox and radio items in menus only when the state change is immediate
and local to the current context.
</p>
<p>
Prefer concise labels. Long explanatory copy belongs in a dialog or popover,
not in a menu row.
</p>
</div>
</article>
<div className="flex items-center justify-center rounded-[var(--radius-lg)] border border-dashed border-[var(--color-border-strong)] bg-[var(--color-background)] p-6">
<ReleaseMenu triggerLabel="Open keyboard-friendly menu" />
</div>
</div>
)
};