import { Button } from "@ai-ui/ui"; import type { Meta, StoryObj } from "@storybook/react"; function FavoriteIcon() { return ( ); } function getButtonFromCanvas(canvasElement: HTMLElement, name: string) { const buttons = canvasElement.querySelectorAll("button, a"); for (const element of buttons) { if (element.textContent?.trim().includes(name)) { return element; } } throw new Error(`Expected to find an interactive control containing "${name}".`); } const meta = { title: "Components/Button", component: Button, args: { children: "Save changes", size: "md", variant: "primary" }, argTypes: { asChild: { control: "boolean", description: "Render through the child element using Radix Slot." }, children: { control: "text", description: "Primary button label." }, className: { control: false }, disabled: { control: "boolean", description: "Disables interaction and sets `data-disabled`." }, loading: { control: "boolean", description: "Shows a spinner, disables interaction, and sets `data-loading`." }, size: { control: "select", options: ["sm", "md", "lg", "icon"], description: "Controls density and spacing." }, type: { control: "radio", options: ["button", "submit", "reset"], description: "Native button type when not using `asChild`." }, variant: { control: "select", options: ["primary", "secondary", "ghost", "subtle", "destructive"], description: "Semantic appearance style." } }, parameters: { docs: { description: { component: "The first production-style component in the system. It demonstrates the Phase 3 pattern: semantic variants, token-driven styling, motion recipes, loading state, stable `data-slot` / `data-*` hooks, and early integration of the `motion` React runtime for refined hover and press animation." } }, layout: "centered" }, tags: ["autodocs"] } satisfies Meta; export default meta; type Story = StoryObj; export const Playground: Story = { play: async ({ canvasElement }) => { const button = getButtonFromCanvas(canvasElement, "Save changes"); button.dispatchEvent(new MouseEvent("click", { bubbles: true })); if (button instanceof HTMLElement) { button.focus(); } } }; export const Variants: Story = { render: () => (
) }; export const Sizes: Story = { render: () => (
) }; export const States: Story = { render: () => (
) }; export const Motion: Story = { parameters: { docs: { description: { story: "Hover and press these buttons directly in the canvas. Primary and subtle variants now use `motion/react` for a restrained lift-and-settle interaction, while loading keeps the label and spinner transitions smooth." } } }, render: () => (

Material motion deck

Buttons should feel like touchable capsules floating over tinted light.

SOFT LIFT
PRESSED
) }; export const AsLink: Story = { render: () => ( ) }; export const Anatomy: Story = { render: () => (

Button anatomy

data-slot="root" on the interactive surface.

data-slot="icon" on the loading spinner when present.

data-slot="label" on the visible button text.

data-loading,{" "} data-disabled,{" "} data-size, and{" "} data-variant drive stateful styling.

) };