{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "all-stories",
  "title": "All Stories",
  "author": "Lloyd Richards <lloyd.d.richards@gmail.com>",
  "description": "Complete collection of all Storybook stories in the registry for bulk installation",
  "registryDependencies": [
    "accordion",
    "alert",
    "alert-dialog",
    "aspect-ratio",
    "avatar",
    "badge",
    "breadcrumb",
    "button",
    "calendar",
    "card",
    "carousel",
    "chart",
    "checkbox",
    "collapsible",
    "dialog",
    "command",
    "context-menu",
    "drawer",
    "dropdown-menu",
    "label",
    "hover-card",
    "input",
    "input-group",
    "input-otp",
    "menubar",
    "navigation-menu",
    "popover",
    "progress",
    "radio-group",
    "resizable",
    "scroll-area",
    "select",
    "separator",
    "sheet",
    "sidebar",
    "skeleton",
    "slider",
    "switch",
    "table",
    "tabs",
    "textarea",
    "toggle",
    "toggle-group",
    "tooltip"
  ],
  "files": [
    {
      "path": "registry/ui/accordion-story/accordion-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport { expect, userEvent, waitFor, within } from \"storybook/test\";\n\nimport {\n  Accordion,\n  AccordionContent,\n  AccordionItem,\n  AccordionTrigger,\n} from \"@/components/ui/accordion\";\n\n/**\n * A vertically stacked set of interactive headings that each reveal a section\n * of content.\n */\nconst meta = {\n  title: \"ui/base/Accordion\",\n  component: Accordion,\n  tags: [\"autodocs\"],\n  argTypes: {\n    multiple: {\n      control: \"boolean\",\n      description: \"Allow multiple accordion items to be open\",\n    },\n    disabled: {\n      control: \"boolean\",\n    },\n  },\n  args: {\n    multiple: false,\n    disabled: false,\n  },\n  render: (args) => (\n    <Accordion {...args}>\n      <AccordionItem value=\"item-1\">\n        <AccordionTrigger>Is it accessible?</AccordionTrigger>\n        <AccordionContent>\n          Yes. It adheres to the WAI-ARIA design pattern.\n        </AccordionContent>\n      </AccordionItem>\n      <AccordionItem value=\"item-2\">\n        <AccordionTrigger>Is it styled?</AccordionTrigger>\n        <AccordionContent>\n          Yes. It comes with default styles that matches the other components'\n          aesthetic.\n        </AccordionContent>\n      </AccordionItem>\n      <AccordionItem value=\"item-3\">\n        <AccordionTrigger>Is it animated?</AccordionTrigger>\n        <AccordionContent>\n          Yes. It's animated by default, but you can disable it if you prefer.\n        </AccordionContent>\n      </AccordionItem>\n    </Accordion>\n  ),\n} satisfies Meta<typeof Accordion>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default behavior of the accordion allows only one item to be open.\n */\nexport const Default: Story = {};\n\nexport const ShouldOnlyOpenOneWhenSingleType: Story = {\n  name: \"when accordions are clicked, should open only one item at a time\",\n  args: {\n    multiple: false,\n  },\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const accordions = await canvas.getAllByRole(\"button\");\n    const expandedCount = () =>\n      accordions.filter(\n        (trigger) => trigger.getAttribute(\"aria-expanded\") === \"true\",\n      ).length;\n\n    // Open the tabs one at a time\n    for (const trigger of accordions) {\n      await userEvent.click(trigger);\n      await waitFor(() => {\n        expect(expandedCount()).toBe(1);\n      });\n    }\n\n    // Close the last opened tab\n    await userEvent.click(accordions[accordions.length - 1]);\n    await waitFor(() => {\n      expect(expandedCount()).toBe(0);\n    });\n  },\n};\n\nexport const ShouldOpenAllWhenMultipleType: Story = {\n  name: \"when accordions are clicked, should open all items one at a time\",\n  args: {\n    multiple: true,\n  },\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const accordions = await canvas.getAllByRole(\"button\");\n    const expandedCount = () =>\n      accordions.filter(\n        (trigger) => trigger.getAttribute(\"aria-expanded\") === \"true\",\n      ).length;\n\n    // Open all tabs one at a time\n    for (let i = 0; i < accordions.length; i++) {\n      await userEvent.click(accordions[i]);\n      await waitFor(() => {\n        expect(expandedCount()).toBe(i + 1);\n      });\n    }\n\n    // Close all tabs one at a time\n    for (let i = accordions.length - 1; i > 0; i--) {\n      await userEvent.click(accordions[i]);\n      await waitFor(() => {\n        expect(expandedCount()).toBe(i);\n      });\n    }\n\n    // Close the last opened tab\n    await userEvent.click(accordions[0]);\n    await waitFor(() => {\n      expect(expandedCount()).toBe(0);\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/alert-story/alert-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport { AlertCircle } from \"lucide-react\";\n\nimport {\n  Alert,\n  AlertDescription,\n  AlertTitle,\n} from \"@/components/ui/alert\";\n\n/**\n * Displays a callout for user attention.\n */\nconst meta = {\n  title: \"ui/base/Alert\",\n  component: Alert,\n  tags: [\"autodocs\"],\n  argTypes: {\n    variant: {\n      options: [\"default\", \"destructive\"],\n      control: { type: \"radio\" },\n    },\n  },\n  args: {\n    variant: \"default\",\n  },\n  render: (args) => (\n    <Alert {...args}>\n      <AlertTitle>Heads up!</AlertTitle>\n      <AlertDescription>\n        You can add components to your app using the cli.\n      </AlertDescription>\n    </Alert>\n  ),\n} satisfies Meta<typeof Alert>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n/**\n * The default form of the alert.\n */\nexport const Default: Story = {};\n\n/**\n * Use the `destructive` alert to indicate a destructive action.\n */\nexport const Destructive: Story = {\n  render: (args) => (\n    <Alert {...args}>\n      <AlertCircle className=\"h-4 w-4\" />\n      <AlertTitle>Error</AlertTitle>\n      <AlertDescription>\n        Your session has expired. Please log in again.\n      </AlertDescription>\n    </Alert>\n  ),\n  args: {\n    variant: \"destructive\",\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/alert-dialog-story/alert-dialog-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  AlertDialog,\n  AlertDialogAction,\n  AlertDialogCancel,\n  AlertDialogContent,\n  AlertDialogDescription,\n  AlertDialogFooter,\n  AlertDialogHeader,\n  AlertDialogTitle,\n  AlertDialogTrigger,\n} from \"@/components/ui/alert-dialog\";\nimport { userEvent, within } from \"storybook/test\";\n\n/**\n * A modal dialog that interrupts the user with important content and expects\n * a response.\n */\nconst meta = {\n  title: \"ui/base/AlertDialog\",\n  component: AlertDialog,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  render: (args) => (\n    <AlertDialog {...args}>\n      <AlertDialogTrigger>Open</AlertDialogTrigger>\n      <AlertDialogContent>\n        <AlertDialogHeader>\n          <AlertDialogTitle>Are you sure absolutely sure?</AlertDialogTitle>\n          <AlertDialogDescription>\n            This action cannot be undone. This will permanently delete your\n            account and remove your data from our servers.\n          </AlertDialogDescription>\n        </AlertDialogHeader>\n        <AlertDialogFooter>\n          <AlertDialogCancel>Cancel</AlertDialogCancel>\n          <AlertDialogAction>Continue</AlertDialogAction>\n        </AlertDialogFooter>\n      </AlertDialogContent>\n    </AlertDialog>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof AlertDialog>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the alert dialog.\n */\nexport const Default: Story = {};\n\nexport const ShouldOpenClose: Story = {\n  name: \"when alert dialog trigger is pressed, should open the dialog and be able to close it\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, canvas, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n\n    await step(\"open the alert dialog\", async () => {\n      await userEvent.click(\n        await canvas.getByRole(\"button\", {\n          name: /open/i,\n        }),\n      );\n    });\n\n    await step(\"close the alert dialog\", async () => {\n      await userEvent.click(\n        await canvasBody.getByRole(\"button\", {\n          name: /cancel/i,\n        }),\n        { delay: 100 },\n      );\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/aspect-ratio-story/aspect-ratio-base.stories.tsx",
      "content": "import Image from \"next/image\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport { AspectRatio } from \"@/components/ui/aspect-ratio\";\n\n/**\n * Displays content within a desired ratio.\n */\nconst meta: Meta<typeof AspectRatio> = {\n  title: \"ui/base/AspectRatio\",\n  component: AspectRatio,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  render: (args) => (\n    <AspectRatio {...args} className=\"bg-slate-50 dark:bg-slate-800\">\n      <Image\n        src=\"https://images.unsplash.com/photo-1576075796033-848c2a5f3696?w=800&dpr=2&q=80\"\n        alt=\"Photo by Alvaro Pinot\"\n        fill\n        unoptimized\n        className=\"rounded-md object-cover\"\n      />\n    </AspectRatio>\n  ),\n  decorators: [\n    (Story) => (\n      <div className=\"w-1/2\">\n        <Story />\n      </div>\n    ),\n  ],\n} satisfies Meta<typeof AspectRatio>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the aspect ratio.\n */\nexport const Default: Story = {\n  args: {\n    ratio: 16 / 9,\n  },\n};\n\n/**\n * Use the `1:1` aspect ratio to display a square image.\n */\nexport const Square: Story = {\n  args: {\n    ratio: 1,\n  },\n};\n\n/**\n * Use the `4:3` aspect ratio to display a landscape image.\n */\nexport const Landscape: Story = {\n  args: {\n    ratio: 4 / 3,\n  },\n};\n\n/**\n * Use the `2.35:1` aspect ratio to display a cinemascope image.\n */\nexport const Cinemascope: Story = {\n  args: {\n    ratio: 2.35 / 1,\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/avatar-story/avatar-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  Avatar,\n  AvatarFallback,\n  AvatarImage,\n} from \"@/components/ui/avatar\";\n\n/**\n * An image element with a fallback for representing the user.\n */\nconst meta = {\n  title: \"ui/base/Avatar\",\n  component: Avatar,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  render: (args) => (\n    <Avatar {...args}>\n      <AvatarImage src=\"https://github.com/shadcn.png\" />\n      <AvatarFallback>CN</AvatarFallback>\n    </Avatar>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Avatar>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the avatar.\n */\nexport const Default: Story = {};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/badge-story/badge-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport { Badge } from \"@/components/ui/badge\";\n\n/**\n * Displays a badge or a component that looks like a badge.\n */\nconst meta = {\n  title: \"ui/base/Badge\",\n  component: Badge,\n  tags: [\"autodocs\"],\n  argTypes: {\n    variant: {\n      control: \"select\",\n      options: [\"default\", \"secondary\", \"destructive\", \"outline\"],\n    },\n    children: {\n      control: \"text\",\n      description: \"Badge content\",\n    },\n  },\n  args: {\n    variant: \"default\",\n    children: \"Badge\",\n  },\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Badge>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the badge.\n */\nexport const Default: Story = {};\n\n/**\n * Use the `secondary` badge to call for less urgent information, blending\n * into the interface while still signaling minor updates or statuses.\n */\nexport const Secondary: Story = {\n  args: {\n    variant: \"secondary\",\n  },\n};\n\n/**\n * Use the `destructive` badge to  indicate errors, alerts, or the need for\n * immediate attention.\n */\nexport const Destructive: Story = {\n  args: {\n    variant: \"destructive\",\n  },\n};\n\n/**\n * Use the `outline` badge for overlaying without obscuring interface details,\n * emphasizing clarity and subtlety..\n */\nexport const Outline: Story = {\n  args: {\n    variant: \"outline\",\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/breadcrumb-story/breadcrumb-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport { ArrowRightSquare } from \"lucide-react\";\n\nimport {\n  Breadcrumb,\n  BreadcrumbItem,\n  BreadcrumbLink,\n  BreadcrumbList,\n  BreadcrumbPage,\n  BreadcrumbSeparator,\n} from \"@/components/ui/breadcrumb\";\n\n/**\n * Displays the path to the current resource using a hierarchy of links.\n */\nconst meta = {\n  title: \"ui/base/Breadcrumb\",\n  component: Breadcrumb,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {},\n  render: (args) => (\n    <Breadcrumb {...args}>\n      <BreadcrumbList>\n        <BreadcrumbItem>\n          <BreadcrumbLink>Home</BreadcrumbLink>\n        </BreadcrumbItem>\n        <BreadcrumbSeparator />\n        <BreadcrumbItem>\n          <BreadcrumbLink>Components</BreadcrumbLink>\n        </BreadcrumbItem>\n        <BreadcrumbSeparator />\n        <BreadcrumbItem>\n          <BreadcrumbPage>Breadcrumb</BreadcrumbPage>\n        </BreadcrumbItem>\n      </BreadcrumbList>\n    </Breadcrumb>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Breadcrumb>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * Displays the path of links to the current resource.\n */\nexport const Default: Story = {};\n\n/**\n * Displays the path with a custom icon for the separator.\n */\nexport const WithCustomSeparator: Story = {\n  render: (args) => (\n    <Breadcrumb {...args}>\n      <BreadcrumbList>\n        <BreadcrumbItem>\n          <BreadcrumbLink>Home</BreadcrumbLink>\n        </BreadcrumbItem>\n        <BreadcrumbSeparator>\n          <ArrowRightSquare />\n        </BreadcrumbSeparator>\n        <BreadcrumbItem>\n          <BreadcrumbLink>Components</BreadcrumbLink>\n        </BreadcrumbItem>\n        <BreadcrumbSeparator>\n          <ArrowRightSquare />\n        </BreadcrumbSeparator>\n        <BreadcrumbItem>\n          <BreadcrumbPage>Breadcrumb</BreadcrumbPage>\n        </BreadcrumbItem>\n      </BreadcrumbList>\n    </Breadcrumb>\n  ),\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/button-story/button-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport { Loader2, Mail } from \"lucide-react\";\n\nimport { Button } from \"@/components/ui/button\";\n\n/**\n * Displays a button or a component that looks like a button.\n */\nconst meta: Meta<typeof Button> = {\n  title: \"ui/base/Button\",\n  component: Button,\n  tags: [\"autodocs\"],\n  argTypes: {\n    variant: {\n      control: \"select\",\n      options: [\n        \"default\",\n        \"destructive\",\n        \"outline\",\n        \"secondary\",\n        \"ghost\",\n        \"link\",\n      ],\n    },\n    size: {\n      control: \"select\",\n      options: [\n        \"default\",\n        \"xs\",\n        \"sm\",\n        \"lg\",\n        \"icon\",\n        \"icon-xs\",\n        \"icon-sm\",\n        \"icon-lg\",\n      ],\n      if: { arg: \"variant\", neq: \"link\" },\n    },\n    children: {\n      control: \"text\",\n    },\n    disabled: {\n      control: \"boolean\",\n    },\n  },\n  parameters: {\n    layout: \"centered\",\n  },\n  args: {\n    variant: \"default\",\n    size: \"default\",\n    children: \"Button\",\n    disabled: false,\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the button, used for primary actions and commands.\n */\nexport const Default: Story = {};\n\n/**\n * Use the `outline` button to reduce emphasis on secondary actions, such as\n * canceling or dismissing a dialog.\n */\nexport const Outline: Story = {\n  args: {\n    variant: \"outline\",\n  },\n};\n\n/**\n * Use the `ghost` button is minimalistic and subtle, for less intrusive\n * actions.\n */\nexport const Ghost: Story = {\n  args: {\n    variant: \"ghost\",\n  },\n};\n\n/**\n * Use the `secondary` button to call for less emphasized actions, styled to\n * complement the primary button while being less conspicuous.\n */\nexport const Secondary: Story = {\n  args: {\n    variant: \"secondary\",\n  },\n};\n\n/**\n * Use the `destructive` button to indicate errors, alerts, or the need for\n * immediate attention.\n */\nexport const Destructive: Story = {\n  args: {\n    variant: \"destructive\",\n  },\n};\n\n/**\n * Use the `link` button to reduce emphasis on tertiary actions, such as\n * hyperlink or navigation, providing a text-only interactive element.\n */\nexport const Link: Story = {\n  args: {\n    variant: \"link\",\n  },\n};\n\n/**\n * Add the `disabled` prop to a button to prevent interactions and add a\n * loading indicator, such as a spinner, to signify an in-progress action.\n */\nexport const Loading: Story = {\n  render: (args) => (\n    <Button {...args}>\n      <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" />\n      Button\n    </Button>\n  ),\n  args: {\n    ...Outline.args,\n    disabled: true,\n  },\n};\n\n/**\n * Add an icon element to a button to enhance visual communication and\n * providing additional context for the action.\n */\nexport const WithIcon: Story = {\n  render: (args) => (\n    <Button {...args}>\n      <Mail className=\"mr-2 h-4 w-4\" /> Login with Email Button\n    </Button>\n  ),\n  args: {\n    ...Secondary.args,\n  },\n};\n\n/**\n * Use the `sm` size for a smaller button, suitable for interfaces needing\n * compact elements without sacrificing usability.\n */\nexport const Small: Story = {\n  args: {\n    size: \"sm\",\n  },\n};\n\n/**\n * Use the `lg` size for a larger button, offering better visibility and\n * easier interaction for users.\n */\nexport const Large: Story = {\n  args: {\n    size: \"lg\",\n  },\n};\n\n/**\n * Use the \"icon\" size for a button with only an icon.\n */\nexport const Icon: Story = {\n  args: {\n    ...Secondary.args,\n    size: \"icon\",\n    title: \"Mail\",\n    children: <Mail />,\n  },\n};\n\n/**\n * Use the `icon-sm` size for a smaller icon-only button.\n */\nexport const IconSmall: Story = {\n  args: {\n    variant: \"secondary\",\n    size: \"icon-sm\",\n    title: \"Mail\",\n    children: <Mail />,\n  },\n};\n\n/**\n * Use the `icon-lg` size for a larger icon-only button.\n */\nexport const IconLarge: Story = {\n  args: {\n    variant: \"secondary\",\n    size: \"icon-lg\",\n    title: \"Mail\",\n    children: <Mail />,\n  },\n};\n\n/**\n * Add the `disabled` prop to prevent interactions with the button.\n */\nexport const Disabled: Story = {\n  args: {\n    disabled: true,\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/calendar-story/calendar-base.stories.tsx",
      "content": "import type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport { addDays } from \"date-fns\";\nimport { action } from \"storybook/actions\";\nimport { expect, userEvent } from \"storybook/test\";\n\nimport { Calendar } from \"@/components/ui/calendar\";\n\n/**\n * A date field component that allows users to enter and edit date.\n */\nconst meta = {\n  title: \"ui/base/Calendar\",\n  component: Calendar,\n  tags: [\"autodocs\"],\n  argTypes: {\n    mode: {\n      table: {\n        disable: true,\n      },\n    },\n    disabled: {\n      control: \"boolean\",\n    },\n    numberOfMonths: {\n      control: \"number\",\n      description: \"Number of months to display\",\n    },\n    showOutsideDays: {\n      control: \"boolean\",\n      description: \"Show days that fall outside the current month\",\n    },\n  },\n  args: {\n    mode: \"single\",\n    selected: new Date(),\n    onSelect: action(\"onDayClick\"),\n    className: \"rounded-md border w-fit\",\n    disabled: false,\n    numberOfMonths: 1,\n    showOutsideDays: true,\n  },\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Calendar>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the calendar.\n */\nexport const Default: Story = {};\n\n/**\n * Use the `multiple` mode to select multiple dates.\n */\nexport const Multiple: Story = {\n  args: {\n    min: 1,\n    selected: [new Date(), addDays(new Date(), 2), addDays(new Date(), 8)],\n    mode: \"multiple\",\n  },\n};\n\n/**\n * Use the `range` mode to select a range of dates.\n */\nexport const Range: Story = {\n  args: {\n    selected: {\n      from: new Date(),\n      to: addDays(new Date(), 7),\n    },\n    mode: \"range\",\n  },\n};\n\n/**\n * Use the `disabled` prop to disable specific dates.\n */\nexport const Disabled: Story = {\n  args: {\n    disabled: [\n      addDays(new Date(), 1),\n      addDays(new Date(), 2),\n      addDays(new Date(), 3),\n      addDays(new Date(), 5),\n    ],\n  },\n};\n\n/**\n * Use the `numberOfMonths` prop to display multiple months.\n */\nexport const MultipleMonths: Story = {\n  args: {\n    numberOfMonths: 2,\n    showOutsideDays: false,\n  },\n};\n\nexport const ShouldNavigateMonthsWhenClicked: Story = {\n  name: \"when using the calendar navigation, should change months\",\n  tags: [\"!dev\", \"!autodocs\"],\n  args: {\n    defaultMonth: new Date(2000, 8),\n  },\n  play: async ({ canvas }) => {\n    const title = await canvas.findByText(/2000/i);\n    const startTitle = title.textContent || \"\";\n    const backBtn = await canvas.findByRole(\"button\", {\n      name: /previous/i,\n    });\n    const nextBtn = await canvas.findByRole(\"button\", {\n      name: /next/i,\n    });\n    const steps = 6;\n    for (let i = 0; i < steps / 2; i++) {\n      await userEvent.click(backBtn);\n      expect(title).not.toHaveTextContent(startTitle);\n    }\n    for (let i = 0; i < steps; i++) {\n      await userEvent.click(nextBtn);\n      if (i == steps / 2 - 1) {\n        expect(title).toHaveTextContent(startTitle);\n        continue;\n      }\n      expect(title).not.toHaveTextContent(startTitle);\n    }\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/card-story/card-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport { BellRing } from \"lucide-react\";\n\nimport { Button } from \"@/components/ui/button\";\nimport {\n  Card,\n  CardAction,\n  CardContent,\n  CardDescription,\n  CardFooter,\n  CardHeader,\n  CardTitle,\n} from \"@/components/ui/card\";\n\nconst notifications = [\n  {\n    title: \"Your call has been confirmed.\",\n    description: \"1 hour ago\",\n  },\n  {\n    title: \"You have a new message!\",\n    description: \"1 hour ago\",\n  },\n  {\n    title: \"Your subscription is expiring soon!\",\n    description: \"2 hours ago\",\n  },\n];\n\n/**\n * Displays a card with header, content, and footer.\n */\nconst meta = {\n  title: \"ui/base/Card\",\n  component: Card,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {\n    className: \"w-96\",\n  },\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Card>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the card.\n */\nexport const Default: Story = {\n  render: (args) => (\n    <Card {...args}>\n      <CardHeader>\n        <CardTitle>Notifications</CardTitle>\n        <CardDescription>You have 3 unread messages.</CardDescription>\n      </CardHeader>\n      <CardContent className=\"grid gap-4\">\n        {notifications.map((notification, index) => (\n          <div key={index} className=\"flex items-center gap-4\">\n            <BellRing className=\"size-6\" />\n            <div>\n              <p>{notification.title}</p>\n              <p className=\"text-foreground/60\">{notification.description}</p>\n            </div>\n          </div>\n        ))}\n      </CardContent>\n      <CardFooter>\n        <Button variant=\"link\">Close</Button>\n      </CardFooter>\n    </Card>\n  ),\n};\n\n/**\n * Use the `CardAction` component to add interactive elements in the header.\n */\nexport const WithCardAction: Story = {\n  render: (args) => (\n    <Card {...args}>\n      <CardHeader>\n        <CardTitle>Team Settings</CardTitle>\n        <CardDescription>Manage your team preferences</CardDescription>\n        <CardAction>\n          <Button size=\"sm\" variant=\"outline\">\n            Edit\n          </Button>\n        </CardAction>\n      </CardHeader>\n      <CardContent>\n        <p>Configure team members, permissions, and notifications.</p>\n      </CardContent>\n      <CardFooter>\n        <Button variant=\"ghost\">Cancel</Button>\n        <Button className=\"ml-auto\">Save Changes</Button>\n      </CardFooter>\n    </Card>\n  ),\n};\n\n/**\n * A minimal card with only content, no header or footer.\n */\nexport const MinimalCard: Story = {\n  render: (args) => (\n    <Card {...args}>\n      <CardContent>\n        <p className=\"text-sm\">\n          This is a minimal card with only content. Perfect for displaying\n          simple information without the need for a header or footer.\n        </p>\n      </CardContent>\n    </Card>\n  ),\n};\n\n/**\n * A card with only a header section, no content or footer.\n */\nexport const HeaderOnly: Story = {\n  render: (args) => (\n    <Card {...args}>\n      <CardHeader>\n        <CardTitle>Quick Stats</CardTitle>\n        <CardDescription>\n          Your account summary at a glance. Click for details.\n        </CardDescription>\n      </CardHeader>\n    </Card>\n  ),\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/carousel-story/carousel-base.stories.tsx",
      "content": "import { expect, userEvent } from \"storybook/test\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  Carousel,\n  CarouselContent,\n  CarouselItem,\n  CarouselNext,\n  CarouselPrevious,\n} from \"@/components/ui/carousel\";\n\n/**\n * A carousel with motion and swipe built using Embla.\n */\nconst meta: Meta<typeof Carousel> = {\n  title: \"ui/base/Carousel\",\n  component: Carousel,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {\n    className: \"w-full max-w-xs\",\n  },\n  render: (args) => (\n    <Carousel {...args}>\n      <CarouselContent>\n        {Array.from({ length: 5 }).map((_, index) => (\n          <CarouselItem key={index}>\n            <div className=\"bg-card flex aspect-square items-center justify-center rounded border p-6\">\n              <span className=\"text-4xl font-semibold\">{index + 1}</span>\n            </div>\n          </CarouselItem>\n        ))}\n      </CarouselContent>\n      <CarouselPrevious />\n      <CarouselNext />\n    </Carousel>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Carousel>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the carousel.\n */\nexport const Default: Story = {};\n\n/**\n * Use the `basis` utility class to change the size of the carousel.\n */\nexport const Size: Story = {\n  render: (args) => (\n    <Carousel {...args} className=\"mx-12 w-full max-w-xs\">\n      <CarouselContent>\n        {Array.from({ length: 5 }).map((_, index) => (\n          <CarouselItem key={index} className=\"basis-1/3\">\n            <div className=\"bg-card flex aspect-square items-center justify-center rounded border p-6\">\n              <span className=\"text-4xl font-semibold\">{index + 1}</span>\n            </div>\n          </CarouselItem>\n        ))}\n      </CarouselContent>\n      <CarouselPrevious />\n      <CarouselNext />\n    </Carousel>\n  ),\n  args: {\n    className: \"mx-12 w-full max-w-xs\",\n  },\n};\n\nexport const ShouldNavigate: Story = {\n  name: \"when clicking next/previous buttons, should navigate through slides\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvas, step }) => {\n    const slides = await canvas.findAllByRole(\"group\");\n    expect(slides).toHaveLength(5);\n    const nextBtn = await canvas.findByRole(\"button\", { name: /next/i });\n    const prevBtn = await canvas.findByRole(\"button\", {\n      name: /previous/i,\n    });\n\n    await step(\"navigate to the last slide\", async () => {\n      for (let i = 0; i < slides.length - 1; i++) {\n        await userEvent.click(nextBtn);\n      }\n    });\n\n    await step(\"navigate back to the first slide\", async () => {\n      for (let i = slides.length - 1; i > 0; i--) {\n        await userEvent.click(prevBtn);\n      }\n    });\n  },\n};\n//\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/chart-story/chart-base.stories.tsx",
      "content": "import { useMemo } from \"react\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport {\n  Area,\n  AreaChart,\n  Bar,\n  BarChart,\n  CartesianGrid,\n  Label,\n  Line,\n  LineChart,\n  Pie,\n  PieChart,\n  XAxis,\n} from \"recharts\";\n\nimport {\n  ChartConfig,\n  ChartContainer,\n  ChartTooltip,\n  ChartTooltipContent,\n} from \"@/components/ui/chart\";\n\nconst multiSeriesData = [\n  { month: \"January\", desktop: 186, mobile: 80 },\n  { month: \"February\", desktop: 305, mobile: 200 },\n  { month: \"March\", desktop: 237, mobile: 120 },\n  { month: \"April\", desktop: 73, mobile: 190 },\n  { month: \"May\", desktop: 209, mobile: 130 },\n  { month: \"June\", desktop: 214, mobile: 140 },\n];\n\nconst multiSeriesConfig = {\n  desktop: {\n    label: \"Desktop\",\n    color: \"var(--chart-1)\",\n  },\n  mobile: {\n    label: \"Mobile\",\n    color: \"var(--chart-2)\",\n  },\n} satisfies ChartConfig;\n\nconst singleSeriesData = [\n  { browser: \"chrome\", visitors: 275, fill: \"var(--color-chrome)\" },\n  { browser: \"safari\", visitors: 200, fill: \"var(--color-safari)\" },\n  { browser: \"other\", visitors: 190, fill: \"var(--color-other)\" },\n];\n\nconst singleSeriesConfig = {\n  visitors: {\n    label: \"Visitors\",\n  },\n  chrome: {\n    label: \"Chrome\",\n    color: \"var(--chart-1)\",\n  },\n  safari: {\n    label: \"Safari\",\n    color: \"var(--chart-2)\",\n  },\n  other: {\n    label: \"Other\",\n    color: \"var(--chart-5)\",\n  },\n} satisfies ChartConfig;\n\n/**\n * Beautiful charts. Built using Recharts. Copy and paste into your apps.\n */\nconst meta = {\n  title: \"ui/base/Chart\",\n  component: ChartContainer,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {\n    children: <div />,\n  },\n} satisfies Meta<typeof ChartContainer>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * Combine multiple Area components to create a stacked area chart.\n */\nexport const StackedAreaChart: Story = {\n  args: {\n    config: multiSeriesConfig,\n  },\n  render: (args) => (\n    <ChartContainer {...args}>\n      <AreaChart\n        accessibilityLayer\n        data={multiSeriesData}\n        margin={{\n          left: 12,\n          right: 12,\n        }}\n      >\n        <CartesianGrid vertical={false} />\n        <XAxis\n          dataKey=\"month\"\n          tickLine={false}\n          axisLine={false}\n          tickMargin={8}\n          tickFormatter={(value) => value.slice(0, 3)}\n        />\n        <ChartTooltip\n          cursor={false}\n          content={<ChartTooltipContent indicator=\"dot\" />}\n        />\n        <Area\n          dataKey=\"mobile\"\n          type=\"natural\"\n          fill=\"var(--color-mobile)\"\n          fillOpacity={0.4}\n          stroke=\"var(--color-mobile)\"\n          stackId=\"a\"\n        />\n        <Area\n          dataKey=\"desktop\"\n          type=\"natural\"\n          fill=\"var(--color-desktop)\"\n          fillOpacity={0.4}\n          stroke=\"var(--color-desktop)\"\n          stackId=\"a\"\n        />\n      </AreaChart>\n    </ChartContainer>\n  ),\n};\n\n/**\n * Combine multiple Bar components to create a stacked bar chart.\n */\nexport const StackedBarChart: Story = {\n  args: {\n    config: multiSeriesConfig,\n  },\n  render: (args) => (\n    <ChartContainer {...args}>\n      <BarChart accessibilityLayer data={multiSeriesData}>\n        <CartesianGrid vertical={false} />\n        <XAxis\n          dataKey=\"month\"\n          tickLine={false}\n          tickMargin={10}\n          axisLine={false}\n          tickFormatter={(value) => value.slice(0, 3)}\n        />\n        <ChartTooltip\n          cursor={false}\n          content={<ChartTooltipContent indicator=\"dashed\" />}\n        />\n        <Bar dataKey=\"desktop\" fill=\"var(--color-desktop)\" radius={4} />\n        <Bar dataKey=\"mobile\" fill=\"var(--color-mobile)\" radius={4} />\n      </BarChart>\n    </ChartContainer>\n  ),\n};\n\n/**\n * Combine multiple Line components to create a single line chart.\n */\nexport const MultiLineChart: Story = {\n  args: {\n    config: multiSeriesConfig,\n  },\n  render: (args) => (\n    <ChartContainer {...args}>\n      <LineChart\n        accessibilityLayer\n        data={multiSeriesData}\n        margin={{\n          left: 12,\n          right: 12,\n        }}\n      >\n        <CartesianGrid vertical={false} />\n        <XAxis\n          dataKey=\"month\"\n          tickLine={false}\n          axisLine={false}\n          tickMargin={8}\n          tickFormatter={(value) => value.slice(0, 3)}\n        />\n        <ChartTooltip\n          cursor={false}\n          content={<ChartTooltipContent hideLabel />}\n        />\n        <Line\n          dataKey=\"desktop\"\n          type=\"natural\"\n          stroke=\"var(--color-desktop)\"\n          strokeWidth={2}\n          dot={false}\n        />\n        <Line\n          dataKey=\"mobile\"\n          type=\"natural\"\n          stroke=\"var(--color-mobile)\"\n          strokeWidth={2}\n          dot={false}\n        />\n      </LineChart>\n    </ChartContainer>\n  ),\n};\n\n/**\n * Combine Pie and Label components to create a doughnut chart.\n */\nexport const DoughnutChart: Story = {\n  args: {\n    config: singleSeriesConfig,\n  },\n  render: (args) => {\n    const totalVisitors = useMemo(() => {\n      return singleSeriesData.reduce((acc, curr) => acc + curr.visitors, 0);\n    }, []);\n    return (\n      <ChartContainer {...args}>\n        <PieChart>\n          <ChartTooltip\n            cursor={false}\n            content={<ChartTooltipContent hideLabel />}\n          />\n          <Pie\n            data={singleSeriesData}\n            dataKey=\"visitors\"\n            nameKey=\"browser\"\n            innerRadius={48}\n            strokeWidth={5}\n          >\n            <Label\n              content={({ viewBox }) => {\n                if (viewBox && \"cx\" in viewBox && \"cy\" in viewBox) {\n                  return (\n                    <text\n                      x={viewBox.cx}\n                      y={viewBox.cy}\n                      textAnchor=\"middle\"\n                      dominantBaseline=\"middle\"\n                    >\n                      <tspan\n                        x={viewBox.cx}\n                        y={viewBox.cy}\n                        className=\"fill-foreground text-3xl font-bold\"\n                      >\n                        {totalVisitors.toLocaleString()}\n                      </tspan>\n                      <tspan\n                        x={viewBox.cx}\n                        y={(viewBox.cy || 0) + 24}\n                        className=\"fill-muted-foreground\"\n                      >\n                        Visitors\n                      </tspan>\n                    </text>\n                  );\n                }\n              }}\n            />\n          </Pie>\n        </PieChart>\n      </ChartContainer>\n    );\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/checkbox-story/checkbox-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport { Checkbox } from \"@/components/ui/checkbox\";\nimport { Label } from \"@/components/ui/label\";\nimport { expect, userEvent, within } from \"storybook/test\";\n\n/**\n * A control that allows the user to toggle between checked and not checked.\n */\nconst meta: Meta<typeof Checkbox> = {\n  title: \"ui/base/Checkbox\",\n  component: Checkbox,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {\n    id: \"terms\",\n    disabled: false,\n  },\n  render: (args) => (\n    <div className=\"flex space-x-2\">\n      <Checkbox {...args} />\n      <Label htmlFor={args.id}>Accept terms and conditions</Label>\n    </div>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Checkbox>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the checkbox.\n */\nexport const Default: Story = {};\n\n/**\n * Use the `disabled` prop to disable the checkbox.\n */\nexport const Disabled: Story = {\n  args: {\n    id: \"disabled-terms\",\n    disabled: true,\n  },\n};\n\nexport const ShouldToggleCheck: Story = {\n  name: \"when the checkbox is clicked, should toggle between checked and not checked\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const checkbox = await canvas.getByRole(\"checkbox\");\n    await userEvent.click(checkbox);\n    expect(checkbox).toBeChecked();\n    await userEvent.click(checkbox, { delay: 100 });\n    expect(checkbox).not.toBeChecked();\n    await userEvent.click(checkbox, { delay: 100 });\n    expect(checkbox).toBeChecked();\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/collapsible-story/collapsible-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport { Info } from \"lucide-react\";\n\nimport {\n  Collapsible,\n  CollapsibleContent,\n  CollapsibleTrigger,\n} from \"@/components/ui/collapsible\";\nimport { expect, userEvent } from \"storybook/test\";\n\n/**\n * An interactive component which expands/collapses a panel.\n */\nconst meta = {\n  title: \"ui/base/Collapsible\",\n  component: Collapsible,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {\n    className: \"w-96\",\n    disabled: false,\n  },\n  render: (args) => (\n    <Collapsible {...args}>\n      <CollapsibleTrigger className=\"flex gap-2\">\n        <h3 className=\"font-semibold\">Can I use this in my project?</h3>\n        <Info className=\"size-6\" />\n      </CollapsibleTrigger>\n      <CollapsibleContent>\n        Yes. Free to use for personal and commercial projects. No attribution\n        required.\n      </CollapsibleContent>\n    </Collapsible>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Collapsible>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the collapsible.\n */\nexport const Default: Story = {};\n\n/**\n * Use the `disabled` prop to disable the interaction.\n */\nexport const Disabled: Story = {\n  args: {\n    disabled: true,\n  },\n};\n\nexport const ShouldOpenClose: Story = {\n  name: \"when collapsable trigger is clicked, should show content\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvas, step }) => {\n    const trigger = await canvas.findByRole(\"button\");\n\n    await step(\"Open the collapsible\", async () => {\n      await userEvent.click(trigger, { delay: 100 });\n      expect(await canvas.queryByText(/yes/i, { exact: true })).toBeVisible();\n    });\n\n    await step(\"Close the collapsible\", async () => {\n      await userEvent.click(trigger, { delay: 100 });\n      expect(await canvas.queryByText(/yes/i, { exact: true })).toBeNull();\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/command-story/command-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  Command,\n  CommandEmpty,\n  CommandGroup,\n  CommandInput,\n  CommandItem,\n  CommandList,\n  CommandSeparator,\n} from \"@/components/ui/command\";\nimport { expect, userEvent, within } from \"storybook/test\";\n\n/**\n * Fast, composable, unstyled command menu for React.\n */\nconst meta = {\n  title: \"ui/base/Command\",\n  component: Command,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {\n    className: \"rounded-lg w-96 border shadow-md\",\n  },\n  render: (args) => (\n    <Command {...args}>\n      <CommandInput placeholder=\"Type a command or search...\" />\n      <CommandList>\n        <CommandEmpty>No results found.</CommandEmpty>\n        <CommandGroup heading=\"Suggestions\">\n          <CommandItem>Calendar</CommandItem>\n          <CommandItem>Search Emoji</CommandItem>\n          <CommandItem disabled>Calculator</CommandItem>\n        </CommandGroup>\n        <CommandSeparator />\n        <CommandGroup heading=\"Settings\">\n          <CommandItem>Profile</CommandItem>\n          <CommandItem>Billing</CommandItem>\n          <CommandItem>Settings</CommandItem>\n        </CommandGroup>\n      </CommandList>\n    </Command>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Command>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the command.\n */\nexport const Default: Story = {};\n\nexport const TypingInCombobox: Story = {\n  name: \"when typing into the combobox, should filter results\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const input = canvas.getByRole(\"combobox\");\n\n    // Search for \"calendar\" which should return a single result\n    await userEvent.type(input, \"calen\", { delay: 100 });\n    expect(canvas.getAllByRole(\"option\", { name: /calendar/i })).toHaveLength(\n      1,\n    );\n\n    await userEvent.clear(input);\n\n    // Search for \"story\" which should return multiple results\n    await userEvent.type(input, \"se\", { delay: 100 });\n    expect(canvas.getAllByRole(\"option\").length).toBeGreaterThan(1);\n    expect(canvas.getAllByRole(\"option\", { name: /search/i })).toHaveLength(1);\n\n    await userEvent.clear(input);\n\n    // Search for \"story\" which should return no results\n    await userEvent.type(input, \"story\", { delay: 100 });\n    expect(canvas.queryAllByRole(\"option\", { hidden: false })).toHaveLength(0);\n    expect(canvas.getByText(/no results/i)).toBeVisible();\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/context-menu-story/context-menu-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  ContextMenu,\n  ContextMenuCheckboxItem,\n  ContextMenuContent,\n  ContextMenuItem,\n  ContextMenuLabel,\n  ContextMenuRadioGroup,\n  ContextMenuRadioItem,\n  ContextMenuSeparator,\n  ContextMenuShortcut,\n  ContextMenuSub,\n  ContextMenuSubContent,\n  ContextMenuSubTrigger,\n  ContextMenuTrigger,\n} from \"@/components/ui/context-menu\";\nimport { expect, userEvent, within } from \"storybook/test\";\n\n/**\n * Displays a menu to the user — such as a set of actions or functions —\n * triggered by a button.\n */\nconst meta = {\n  title: \"ui/base/ContextMenu\",\n  component: ContextMenu,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {},\n  render: (args) => (\n    <ContextMenu {...args}>\n      <ContextMenuTrigger className=\"bg-accent flex h-48 w-96 items-center justify-center rounded-md border border-dashed text-sm\">\n        Right click here\n      </ContextMenuTrigger>\n      <ContextMenuContent className=\"w-32\">\n        <ContextMenuItem>Profile</ContextMenuItem>\n        <ContextMenuItem>Billing</ContextMenuItem>\n        <ContextMenuItem>Team</ContextMenuItem>\n        <ContextMenuItem>Subscription</ContextMenuItem>\n      </ContextMenuContent>\n    </ContextMenu>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof ContextMenu>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the context menu.\n */\nexport const Default: Story = {};\n\n/**\n * A context menu with shortcuts.\n */\nexport const WithShortcuts: Story = {\n  render: (args) => (\n    <ContextMenu {...args}>\n      <ContextMenuTrigger className=\"bg-accent flex h-48 w-96 items-center justify-center rounded-md border border-dashed text-sm\">\n        Right click here\n      </ContextMenuTrigger>\n      <ContextMenuContent className=\"w-32\">\n        <ContextMenuItem>\n          Back\n          <ContextMenuShortcut>⌘[</ContextMenuShortcut>\n        </ContextMenuItem>\n        <ContextMenuItem disabled>\n          Forward\n          <ContextMenuShortcut>⌘]</ContextMenuShortcut>\n        </ContextMenuItem>\n        <ContextMenuItem>\n          Reload\n          <ContextMenuShortcut>⌘R</ContextMenuShortcut>\n        </ContextMenuItem>\n      </ContextMenuContent>\n    </ContextMenu>\n  ),\n};\n\n/**\n * A context menu with a submenu.\n */\nexport const WithSubmenu: Story = {\n  render: (args) => (\n    <ContextMenu {...args}>\n      <ContextMenuTrigger className=\"bg-accent flex h-48 w-96 items-center justify-center rounded-md border border-dashed text-sm\">\n        Right click here\n      </ContextMenuTrigger>\n      <ContextMenuContent className=\"w-32\">\n        <ContextMenuItem>\n          New Tab\n          <ContextMenuShortcut>⌘N</ContextMenuShortcut>\n        </ContextMenuItem>\n        <ContextMenuSub>\n          <ContextMenuSubTrigger>More Tools</ContextMenuSubTrigger>\n          <ContextMenuSubContent>\n            <ContextMenuItem>\n              Save Page As...\n              <ContextMenuShortcut>⇧⌘S</ContextMenuShortcut>\n            </ContextMenuItem>\n            <ContextMenuItem>Create Shortcut...</ContextMenuItem>\n            <ContextMenuItem>Name Window...</ContextMenuItem>\n            <ContextMenuSeparator />\n            <ContextMenuItem>Developer Tools</ContextMenuItem>\n          </ContextMenuSubContent>\n        </ContextMenuSub>\n      </ContextMenuContent>\n    </ContextMenu>\n  ),\n};\n\n/**\n * A context menu with checkboxes.\n */\nexport const WithCheckboxes: Story = {\n  render: (args) => (\n    <ContextMenu {...args}>\n      <ContextMenuTrigger className=\"bg-accent flex h-48 w-96 items-center justify-center rounded-md border border-dashed text-sm\">\n        Right click here\n      </ContextMenuTrigger>\n      <ContextMenuContent className=\"w-64\">\n        <ContextMenuCheckboxItem checked>\n          Show Comments\n          <ContextMenuShortcut>⌘⇧C</ContextMenuShortcut>\n        </ContextMenuCheckboxItem>\n        <ContextMenuCheckboxItem>Show Preview</ContextMenuCheckboxItem>\n      </ContextMenuContent>\n    </ContextMenu>\n  ),\n};\n\n/**\n * A context menu with a radio group.\n */\nexport const WithRadioGroup: Story = {\n  render: (args) => (\n    <ContextMenu {...args}>\n      <ContextMenuTrigger className=\"bg-accent flex h-48 w-96 items-center justify-center rounded-md border border-dashed text-sm\">\n        Right click here\n      </ContextMenuTrigger>\n      <ContextMenuContent className=\"w-64\">\n        <ContextMenuRadioGroup value=\"light\">\n          <ContextMenuLabel inset>Theme</ContextMenuLabel>\n          <ContextMenuRadioItem value=\"light\">Light</ContextMenuRadioItem>\n          <ContextMenuRadioItem value=\"dark\">Dark</ContextMenuRadioItem>\n        </ContextMenuRadioGroup>\n      </ContextMenuContent>\n    </ContextMenu>\n  ),\n};\n\nexport const ShouldOpenClose: Story = {\n  name: \"when right-clicking the trigger area, the menu appears and can be interacted with\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, canvas, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n\n    step(\"Right-click on the trigger area\", async () => {\n      await userEvent.pointer({\n        keys: \"[MouseRight>]\",\n        target: await canvas.findByText(/click here/i),\n        coords: {\n          x: canvasElement.clientWidth / 2,\n          y: canvasElement.clientHeight / 2,\n        },\n      });\n    });\n    expect(await canvasBody.findByRole(\"menu\")).toBeInTheDocument();\n    const items = await canvasBody.findAllByRole(\"menuitem\");\n    expect(items).toHaveLength(4);\n\n    step(\"Click the first menu item\", async () => {\n      await userEvent.click(items[0], { delay: 100 });\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/date-picker-story/date-picker-base.stories.tsx",
      "content": "import { expect, userEvent, waitFor, within } from \"storybook/test\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Calendar } from \"@/components/ui/calendar\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger,\n} from \"@/components/ui/popover\";\nimport { CalendarIcon, ChevronDownIcon } from \"lucide-react\";\nimport { useState } from \"react\";\nimport { action } from \"storybook/actions\";\n\n/**\n * A window overlaid on either the primary window or another dialog window,\n * rendering the content underneath inert.\n */\nconst meta = {\n  title: \"ui/base/DatePicker\",\n  component: Calendar,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Calendar>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * Combination of the calendar and a button that opens a popover.\n */\nexport const WithPopover: Story = {\n  args: {\n    captionLayout: \"dropdown\",\n  },\n\n  render: (args) => {\n    const [open, setOpen] = useState(false);\n    const [date, setDate] = useState<Date | undefined>(undefined);\n    return (\n      <div className=\"flex flex-col gap-3\">\n        <Label htmlFor=\"date\" className=\"px-1\">\n          Date of birth\n        </Label>\n        <Popover open={open} onOpenChange={setOpen}>\n          <PopoverTrigger\n            render={\n              <Button\n                variant=\"outline\"\n                id=\"date\"\n                className=\"w-48 justify-between font-normal\"\n              />\n            }\n          >\n            {date ? date.toLocaleDateString() : \"Select date\"}\n            <ChevronDownIcon />\n          </PopoverTrigger>\n          <PopoverContent className=\"w-auto overflow-hidden p-0\" align=\"start\">\n            <Calendar\n              {...args}\n              mode=\"single\"\n              selected={date}\n              onSelect={(date) => {\n                setDate(date);\n                setOpen(false);\n                action(\"date selected\")(date);\n              }}\n            />\n          </PopoverContent>\n        </Popover>\n      </div>\n    );\n  },\n};\n\nexport const ShouldOpenPopover: Story = {\n  ...WithPopover,\n  name: \"when clicking the button, should open the popover to select a date\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement.ownerDocument.body);\n    await step(\"Open the popover\", async () => {\n      await userEvent.click(\n        await canvas.findByRole(\"button\", { name: \"Date of birth\" }),\n      );\n      await waitFor(() =>\n        expect(\n          canvasElement.ownerDocument.body.querySelector(\".rdp-root\"),\n        ).toBeVisible(),\n      );\n    });\n    await step(\"Select a date\", async () => {\n      const dateButtons = await canvas.findAllByRole(\"button\", {\n        name: /1st/i,\n      });\n      await userEvent.click(dateButtons[0]);\n    });\n  },\n};\n\nconst formatDate = (date: Date | undefined) => {\n  return date\n    ? date.toLocaleDateString(\"en-US\", {\n        day: \"2-digit\",\n        month: \"long\",\n        year: \"numeric\",\n      })\n    : \"\";\n};\n\nconst isValidDate = (date: Date | undefined) =>\n  date ? !isNaN(date.getTime()) : false;\n\n/**\n * Combination of the calendar and an input field that allows typing a date.\n */\nexport const WithInput: Story = {\n  args: {\n    captionLayout: \"dropdown\",\n  },\n\n  render: (args) => {\n    const [open, setOpen] = useState(false);\n    const [date, setDate] = useState<Date | undefined>(new Date(\"2025-06-01\"));\n    const [month, setMonth] = useState<Date | undefined>(date);\n    const [value, setValue] = useState(formatDate(date));\n\n    return (\n      <div className=\"flex flex-col gap-3\">\n        <Label htmlFor=\"date\" className=\"px-1\">\n          Subscription Date\n        </Label>\n        <div className=\"relative flex gap-2\">\n          <Input\n            id=\"date\"\n            value={value}\n            placeholder=\"June 01, 2025\"\n            className=\"bg-background pr-10\"\n            onChange={(e) => {\n              const date = new Date(e.target.value);\n              setValue(e.target.value);\n              if (isValidDate(date)) {\n                setDate(date);\n                setMonth(date);\n                action(\"date input changed\")(date);\n              }\n            }}\n            onKeyDown={(e) => {\n              if (e.key === \"ArrowDown\") {\n                e.preventDefault();\n                setOpen(true);\n              }\n            }}\n          />\n          <Popover open={open} onOpenChange={setOpen}>\n            <PopoverTrigger\n              render={\n                <Button\n                  id=\"date-picker\"\n                  variant=\"ghost\"\n                  className=\"absolute top-1/2 right-2 size-6 -translate-y-1/2\"\n                />\n              }\n            >\n              <CalendarIcon className=\"size-3.5\" />\n              <span className=\"sr-only\">Select date</span>\n            </PopoverTrigger>\n            <PopoverContent\n              className=\"w-auto overflow-hidden p-0\"\n              align=\"end\"\n              alignOffset={-8}\n              sideOffset={10}\n            >\n              <Calendar\n                {...args}\n                mode=\"single\"\n                selected={date}\n                month={month}\n                onMonthChange={setMonth}\n                onSelect={(date) => {\n                  setDate(date);\n                  setValue(formatDate(date));\n                  setOpen(false);\n                  action(\"date selected\")(date);\n                }}\n              />\n            </PopoverContent>\n          </Popover>\n        </div>\n      </div>\n    );\n  },\n};\n\nexport const ShouldEnterTextDate: Story = {\n  ...WithInput,\n  name: \"when typing a valid date, should update the input and close the calendar\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement.ownerDocument.body);\n    const input = await canvas.findByRole(\"textbox\", {\n      name: \"Subscription Date\",\n    });\n    await step(\"type a date\", async () => {\n      await userEvent.click(input);\n      await userEvent.clear(input);\n      await userEvent.type(input, \"July 21, 1999\");\n      await userEvent.keyboard(\"{enter}\");\n      expect(input).toHaveValue(\"July 21, 1999\");\n    });\n\n    await step(\"check the calendar\", async () => {\n      await userEvent.click(\n        await canvas.findByRole(\"button\", { name: \"Select date\" }),\n      );\n      await waitFor(() =>\n        expect(\n          canvas.queryByRole(\"button\", {\n            name: \"Wednesday, July 21st, 1999, selected\",\n          }),\n        ).toBeVisible(),\n      );\n    });\n  },\n};\n\n/**\n * Combination of the calendar and an input field that allows changing the time.\n */\nexport const WithDateTime: Story = {\n  args: {\n    captionLayout: \"dropdown\",\n  },\n\n  render: (args) => {\n    const [open, setOpen] = useState(false);\n    const [date, setDate] = useState<Date | undefined>(undefined);\n    return (\n      <div className=\"flex gap-4\">\n        <div className=\"flex flex-col gap-3\">\n          <Label htmlFor=\"date-picker\" className=\"px-1\">\n            Date\n          </Label>\n          <Popover open={open} onOpenChange={setOpen}>\n            <PopoverTrigger\n              render={\n                <Button\n                  variant=\"outline\"\n                  id=\"date-picker\"\n                  className=\"w-32 justify-between font-normal\"\n                />\n              }\n            >\n              {date ? date.toLocaleDateString() : \"Select date\"}\n              <ChevronDownIcon />\n            </PopoverTrigger>\n            <PopoverContent\n              className=\"w-auto overflow-hidden p-0\"\n              align=\"start\"\n            >\n              <Calendar\n                {...args}\n                mode=\"single\"\n                selected={date}\n                onSelect={(date) => {\n                  setDate(date);\n                  setOpen(false);\n                  action(\"date selected\")(date);\n                }}\n              />\n            </PopoverContent>\n          </Popover>\n        </div>\n        <div className=\"flex flex-col gap-3\">\n          <Label htmlFor=\"time-picker\" className=\"px-1\">\n            Time\n          </Label>\n          <Input\n            type=\"time\"\n            id=\"time-picker\"\n            step=\"1\"\n            disabled={!date}\n            defaultValue=\"10:30:00\"\n            onChange={(e) => {\n              if (!date) {\n                return;\n              }\n              const [hours, minutes, seconds] = e.target.value\n                .split(\":\")\n                .map(Number);\n              date.setHours(hours, minutes, seconds);\n              setDate(date);\n              action(\"time selected\")(date);\n            }}\n            className=\"bg-background appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none\"\n          />\n        </div>\n      </div>\n    );\n  },\n};\n\nexport const ShouldOpenCalendar: Story = {\n  ...WithDateTime,\n  name: \"when clicking the date button, should open the calendar to select a date\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement.ownerDocument.body);\n\n    await step(\"Open the date popover\", async () => {\n      const dateInput = await canvas.findByLabelText(\"Date\");\n      await userEvent.click(dateInput);\n      await waitFor(() =>\n        expect(\n          canvas.queryAllByRole(\"button\", { name: /1st/i }).at(0),\n        ).toBeVisible(),\n      );\n    });\n\n    const dateButtons = await canvas.findAllByRole(\"button\", { name: /1st/i });\n    await userEvent.click(dateButtons[0]);\n\n    await step(\"type a time\", async () => {\n      const timeInput = await canvas.findByLabelText(\"Time\");\n      await userEvent.click(timeInput);\n      await userEvent.type(timeInput, \"1\");\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/dialog-story/dialog-base.stories.tsx",
      "content": "import { expect, userEvent, waitFor, within } from \"storybook/test\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  Dialog,\n  DialogClose,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n  DialogTrigger,\n} from \"@/components/ui/dialog\";\n\n/**\n * A window overlaid on either the primary window or another dialog window,\n * rendering the content underneath inert.\n */\nconst meta = {\n  title: \"ui/base/Dialog\",\n  component: Dialog,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  render: (args) => (\n    <Dialog {...args}>\n      <DialogTrigger>Open</DialogTrigger>\n      <DialogContent>\n        <DialogHeader>\n          <DialogTitle>Are you absolutely sure?</DialogTitle>\n          <DialogDescription>\n            This action cannot be undone. This will permanently delete your\n            account and remove your data from our servers.\n          </DialogDescription>\n        </DialogHeader>\n        <DialogFooter className=\"gap-4\">\n          <DialogClose className=\"hover:underline\">Cancel</DialogClose>\n          <DialogClose className=\"bg-primary text-primary-foreground rounded px-4 py-2\">\n            Continue\n          </DialogClose>\n        </DialogFooter>\n      </DialogContent>\n    </Dialog>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Dialog>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the dialog.\n */\nexport const Default: Story = {};\n\nexport const ShouldOpenCloseWithContinue: Story = {\n  name: \"when clicking Continue button, should close the dialog\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n\n    await step(\"Open the dialog\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /open/i }),\n      );\n      const dialog = await canvasBody.findByRole(\"dialog\");\n      await waitFor(() => {\n        expect(dialog).toHaveAttribute(\"data-open\");\n      });\n    });\n\n    await step(\"Close the dialog\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /continue/i }),\n      );\n      await waitFor(() => {\n        expect(canvasBody.queryByRole(\"dialog\")).not.toBeInTheDocument();\n      });\n    });\n  },\n};\n\nexport const ShouldOpenCloseWithCancel: Story = {\n  name: \"when clicking Cancel button, should close the dialog\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n\n    await step(\"Open the dialog\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /open/i }),\n      );\n      const dialog = await canvasBody.findByRole(\"dialog\");\n      await waitFor(() => {\n        expect(dialog).toHaveAttribute(\"data-open\");\n      });\n    });\n\n    await step(\"Close the dialog\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /cancel/i }),\n      );\n      await waitFor(() => {\n        expect(canvasBody.queryByRole(\"dialog\")).not.toBeInTheDocument();\n      });\n    });\n  },\n};\n\nexport const ShouldOpenCloseCross: Story = {\n  name: \"when clicking Close icon, should close the dialog\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n\n    await step(\"Open the dialog\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /open/i }),\n      );\n      const dialog = await canvasBody.findByRole(\"dialog\");\n      await waitFor(() => {\n        expect(dialog).toHaveAttribute(\"data-open\");\n      });\n    });\n\n    await step(\"Close the dialog\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /close/i }),\n      );\n      await waitFor(() => {\n        expect(canvasBody.queryByRole(\"dialog\")).not.toBeInTheDocument();\n      });\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/drawer-story/drawer-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  Drawer,\n  DrawerClose,\n  DrawerContent,\n  DrawerDescription,\n  DrawerFooter,\n  DrawerHeader,\n  DrawerTitle,\n  DrawerTrigger,\n} from \"@/components/ui/drawer\";\nimport { expect, fn, userEvent, within } from \"storybook/test\";\n\n/**\n * A drawer component for React.\n */\nconst meta = {\n  title: \"ui/base/Drawer\",\n  component: Drawer,\n  tags: [\"autodocs\"],\n  args: {\n    onOpenChange: fn(),\n    onClose: fn(),\n    onAnimationEnd: fn(),\n  },\n  render: (args) => (\n    <Drawer {...args}>\n      <DrawerTrigger>Open</DrawerTrigger>\n      <DrawerContent>\n        <DrawerHeader>\n          <DrawerTitle>Are you sure absolutely sure?</DrawerTitle>\n          <DrawerDescription>This action cannot be undone.</DrawerDescription>\n        </DrawerHeader>\n        <DrawerFooter>\n          <DrawerClose className=\"bg-primary text-primary-foreground rounded px-4 py-2\">\n            Submit\n          </DrawerClose>\n          <DrawerClose className=\"hover:underline\">Cancel</DrawerClose>\n        </DrawerFooter>\n      </DrawerContent>\n    </Drawer>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Drawer>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the drawer.\n */\nexport const Default: Story = {};\n\nexport const ShouldOpenCloseWithSubmit: Story = {\n  name: \"when clicking Submit button, should close the drawer\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ args, canvasElement, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n\n    await step(\"Open the drawer\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /open/i }),\n      );\n      await expect(args.onOpenChange).toHaveBeenCalled();\n\n      const dialog = await canvasBody.findByRole(\"dialog\");\n      expect(dialog).toBeInTheDocument();\n      expect(dialog).toHaveAttribute(\"data-state\", \"open\");\n    });\n\n    await step(\"Close the drawer\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /submit/i }),\n        { delay: 100 },\n      );\n      await expect(args.onClose).toHaveBeenCalled();\n      expect(await canvasBody.findByRole(\"dialog\")).toHaveAttribute(\n        \"data-state\",\n        \"closed\",\n      );\n    });\n  },\n};\n\nexport const ShouldOpenCloseWithCancel: Story = {\n  name: \"when clicking Cancel button, should close the drawer\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ args, canvasElement, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n\n    await step(\"Open the drawer\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /open/i }),\n      );\n      await expect(args.onOpenChange).toHaveBeenCalled();\n\n      const dialog = await canvasBody.findByRole(\"dialog\");\n      expect(dialog).toBeInTheDocument();\n      expect(dialog).toHaveAttribute(\"data-state\", \"open\");\n    });\n\n    await step(\"Close the drawer\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /cancel/i }),\n        { delay: 100 },\n      );\n      await expect(args.onClose).toHaveBeenCalled();\n      expect(await canvasBody.findByRole(\"dialog\")).toHaveAttribute(\n        \"data-state\",\n        \"closed\",\n      );\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/dropdown-menu-story/dropdown-menu-base.stories.tsx",
      "content": "import { expect, userEvent, waitFor, within } from \"storybook/test\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport { Mail, Plus, PlusCircle, Search, UserPlus } from \"lucide-react\";\n\nimport {\n  DropdownMenu,\n  DropdownMenuCheckboxItem,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuPortal,\n  DropdownMenuRadioGroup,\n  DropdownMenuRadioItem,\n  DropdownMenuSeparator,\n  DropdownMenuShortcut,\n  DropdownMenuSub,\n  DropdownMenuSubContent,\n  DropdownMenuSubTrigger,\n  DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\n\n/**\n * Displays a menu to the user — such as a set of actions or functions —\n * triggered by a button.\n */\nconst meta = {\n  title: \"ui/base/DropdownMenu\",\n  component: DropdownMenu,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  render: (args) => (\n    <DropdownMenu {...args}>\n      <DropdownMenuTrigger>Open</DropdownMenuTrigger>\n      <DropdownMenuContent className=\"w-44\">\n        <DropdownMenuGroup>\n          <DropdownMenuLabel>My Account</DropdownMenuLabel>\n          <DropdownMenuSeparator />\n          <DropdownMenuItem>Profile</DropdownMenuItem>\n          <DropdownMenuItem>Billing</DropdownMenuItem>\n          <DropdownMenuItem>Team</DropdownMenuItem>\n          <DropdownMenuItem>Subscription</DropdownMenuItem>\n        </DropdownMenuGroup>\n      </DropdownMenuContent>\n    </DropdownMenu>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof DropdownMenu>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the dropdown menu.\n */\nexport const Default: Story = {};\n\n/**\n * A dropdown menu with shortcuts.\n */\nexport const WithShortcuts: Story = {\n  render: (args) => (\n    <DropdownMenu {...args}>\n      <DropdownMenuTrigger>Open</DropdownMenuTrigger>\n      <DropdownMenuContent className=\"w-44\">\n        <DropdownMenuLabel>Controls</DropdownMenuLabel>\n        <DropdownMenuItem>\n          Back\n          <DropdownMenuShortcut>⌘[</DropdownMenuShortcut>\n        </DropdownMenuItem>\n        <DropdownMenuItem disabled>\n          Forward\n          <DropdownMenuShortcut>⌘]</DropdownMenuShortcut>\n        </DropdownMenuItem>\n      </DropdownMenuContent>\n    </DropdownMenu>\n  ),\n};\n\n/**\n * A dropdown menu with submenus.\n */\nexport const WithSubmenus: Story = {\n  render: (args) => (\n    <DropdownMenu {...args}>\n      <DropdownMenuTrigger>Open</DropdownMenuTrigger>\n      <DropdownMenuContent className=\"w-44\">\n        <DropdownMenuItem>\n          <Search className=\"mr-2 size-4\" />\n          <span>Search</span>\n        </DropdownMenuItem>\n        <DropdownMenuSeparator />\n        <DropdownMenuGroup>\n          <DropdownMenuItem>\n            <Plus className=\"mr-2 size-4\" />\n            <span>New Team</span>\n            <DropdownMenuShortcut>⌘+T</DropdownMenuShortcut>\n          </DropdownMenuItem>\n          <DropdownMenuSub>\n            <DropdownMenuSubTrigger>\n              <UserPlus className=\"mr-2 size-4\" />\n              <span>Invite users</span>\n            </DropdownMenuSubTrigger>\n            <DropdownMenuPortal>\n              <DropdownMenuSubContent>\n                <DropdownMenuItem>\n                  <Mail className=\"mr-2 size-4\" />\n                  <span>Email</span>\n                </DropdownMenuItem>\n                <DropdownMenuSeparator />\n                <DropdownMenuItem>\n                  <PlusCircle className=\"mr-2 size-4\" />\n                  <span>More...</span>\n                </DropdownMenuItem>\n              </DropdownMenuSubContent>\n            </DropdownMenuPortal>\n          </DropdownMenuSub>\n        </DropdownMenuGroup>\n      </DropdownMenuContent>\n    </DropdownMenu>\n  ),\n};\n\n/**\n * A dropdown menu with radio items.\n */\nexport const WithRadioItems: Story = {\n  render: (args) => (\n    <DropdownMenu {...args}>\n      <DropdownMenuTrigger>Open</DropdownMenuTrigger>\n      <DropdownMenuContent className=\"w-44\">\n        <DropdownMenuLabel inset>Status</DropdownMenuLabel>\n        <DropdownMenuRadioGroup value=\"warning\">\n          <DropdownMenuRadioItem value=\"info\">Info</DropdownMenuRadioItem>\n          <DropdownMenuRadioItem value=\"warning\">Warning</DropdownMenuRadioItem>\n          <DropdownMenuRadioItem value=\"error\">Error</DropdownMenuRadioItem>\n        </DropdownMenuRadioGroup>\n      </DropdownMenuContent>\n    </DropdownMenu>\n  ),\n};\n\n/**\n * A dropdown menu with checkboxes.\n */\nexport const WithCheckboxes: Story = {\n  render: (args) => (\n    <DropdownMenu {...args}>\n      <DropdownMenuTrigger>Open</DropdownMenuTrigger>\n      <DropdownMenuContent className=\"w-44\">\n        <DropdownMenuCheckboxItem checked>\n          Autosave\n          <DropdownMenuShortcut>⌘S</DropdownMenuShortcut>\n        </DropdownMenuCheckboxItem>\n        <DropdownMenuCheckboxItem>Show Comments</DropdownMenuCheckboxItem>\n      </DropdownMenuContent>\n    </DropdownMenu>\n  ),\n};\n\nexport const ShouldOpenClose: Story = {\n  name: \"when clicking an item, should close the dropdown menu\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const body = within(canvasElement.ownerDocument.body);\n\n    await step(\"Open the dropdown menu\", async () => {\n      await userEvent.click(await body.findByRole(\"button\", { name: /open/i }));\n      expect(await body.findByRole(\"menu\")).toBeInTheDocument();\n    });\n\n    await step(\"Click the first menu item\", async () => {\n      const items = await body.findAllByRole(\"menuitem\");\n      expect(items).toHaveLength(4);\n      await userEvent.click(items[0], { delay: 100 });\n      await waitFor(() => {\n        expect(body.queryByRole(\"menu\")).not.toBeInTheDocument();\n      });\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/form-story/form-react-hook-base.stories.tsx",
      "content": "import { zodResolver } from \"@hookform/resolvers/zod\";\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport type { ComponentProps } from \"react\";\nimport { Controller, useForm } from \"react-hook-form\";\nimport { action } from \"storybook/actions\";\nimport { expect, userEvent } from \"storybook/test\";\nimport * as z from \"zod\";\n\nimport { Button } from \"@/components/ui/button\";\nimport {\n  Field,\n  FieldDescription,\n  FieldError,\n  FieldGroup,\n  FieldLabel,\n} from \"@/components/ui/field\";\nimport { Input } from \"@/components/ui/input\";\n\nconst formSchema = z.object({\n  username: z.string().min(6, {\n    message: \"Username must be at least 6 characters.\",\n  }),\n});\n\ntype ProfileFormValues = z.infer<typeof formSchema>;\n\nfunction ReactHookFormProfileForm(props: ComponentProps<\"form\">) {\n  const form = useForm<ProfileFormValues>({\n    resolver: zodResolver(formSchema),\n    defaultValues: {\n      username: \"\",\n    },\n  });\n  function onSubmit(values: ProfileFormValues) {\n    action(\"onSubmit\")(values);\n  }\n  return (\n    <form\n      onSubmit={form.handleSubmit(onSubmit)}\n      className=\"space-y-8\"\n      {...props}\n    >\n      <FieldGroup>\n        <Controller\n          control={form.control}\n          name=\"username\"\n          render={({ field, fieldState }) => (\n            <Field data-invalid={fieldState.invalid}>\n              <FieldLabel htmlFor=\"form-rhf-username\">Username</FieldLabel>\n              <Input\n                id=\"form-rhf-username\"\n                placeholder=\"username\"\n                aria-invalid={fieldState.invalid}\n                {...field}\n              />\n              <FieldDescription>\n                This is your public display name.\n              </FieldDescription>\n              {fieldState.invalid && <FieldError errors={[fieldState.error]} />}\n            </Field>\n          )}\n        />\n      </FieldGroup>\n      <Button type=\"submit\">Submit</Button>\n    </form>\n  );\n}\n\n/**\n * Building forms with React Hook Form and Zod.\n */\nconst meta: Meta<typeof ReactHookFormProfileForm> = {\n  title: \"ui/base/Form (React Hook Form)\",\n  component: ReactHookFormProfileForm,\n  tags: [\"autodocs\"],\n  argTypes: {},\n} satisfies Meta<typeof ReactHookFormProfileForm>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the form.\n */\nexport const Default: Story = {};\n\nexport const ShouldSucceedWhenValidInput: Story = {\n  name: \"when typing a valid username, should not show an error message\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvas, step }) => {\n    await step(\"Type a valid username\", async () => {\n      await userEvent.type(\n        await canvas.findByRole(\"textbox\", { name: /username/i }),\n        \"mockuser\",\n      );\n    });\n\n    await step(\"Click the submit button\", async () => {\n      await userEvent.click(\n        await canvas.findByRole(\"button\", { name: /submit/i }),\n      );\n      expect(\n        await canvas.queryByText(/username must be at least 6 characters/i, {\n          exact: true,\n        }),\n      ).toBeNull();\n    });\n  },\n};\n\nexport const ShouldShowErrorWhenInvalidInput: Story = {\n  name: \"when typing a short username, should show an error message\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvas, step }) => {\n    await step(\"Type a short username\", async () => {\n      await userEvent.type(\n        await canvas.findByRole(\"textbox\", { name: /username/i }),\n        \"fail\",\n      );\n    });\n\n    await step(\"Click the submit button\", async () => {\n      await userEvent.click(\n        await canvas.findByRole(\"button\", { name: /submit/i }),\n      );\n      expect(\n        await canvas.queryByText(/username must be at least 6 characters/i, {\n          exact: true,\n        }),\n      ).toBeVisible();\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/form-story/form-tanstack-base.stories.tsx",
      "content": "import type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport { useForm as useTanstackForm } from \"@tanstack/react-form\";\nimport type { ComponentProps } from \"react\";\nimport { action } from \"storybook/actions\";\nimport { expect, userEvent } from \"storybook/test\";\nimport * as z from \"zod\";\n\nimport { Button } from \"@/components/ui/button\";\nimport {\n  Field,\n  FieldDescription,\n  FieldError,\n  FieldGroup,\n  FieldLabel,\n} from \"@/components/ui/field\";\nimport { Input } from \"@/components/ui/input\";\n\nconst formSchema = z.object({\n  username: z.string().min(6, {\n    message: \"Username must be at least 6 characters.\",\n  }),\n});\n\ntype ProfileFormValues = z.infer<typeof formSchema>;\n\nfunction TanStackFormProfileForm(props: ComponentProps<\"form\">) {\n  const form = useTanstackForm({\n    defaultValues: {\n      username: \"\",\n    },\n    validators: {\n      onSubmit: formSchema,\n    },\n    onSubmit: async ({ value }) => {\n      action(\"onSubmit\")(value as ProfileFormValues);\n    },\n  });\n\n  return (\n    <form\n      onSubmit={(event) => {\n        event.preventDefault();\n        form.handleSubmit();\n      }}\n      className=\"space-y-8\"\n      {...props}\n    >\n      <FieldGroup>\n        <form.Field name=\"username\">\n          {(field) => {\n            const isInvalid =\n              field.state.meta.isTouched && !field.state.meta.isValid;\n            return (\n              <Field data-invalid={isInvalid}>\n                <FieldLabel htmlFor=\"form-tanstack-username\">\n                  Username\n                </FieldLabel>\n                <Input\n                  id=\"form-tanstack-username\"\n                  name={field.name}\n                  placeholder=\"username\"\n                  value={field.state.value}\n                  onBlur={field.handleBlur}\n                  onChange={(event) => field.handleChange(event.target.value)}\n                  aria-invalid={isInvalid}\n                />\n                <FieldDescription>\n                  This is your public display name.\n                </FieldDescription>\n                {isInvalid && (\n                  <FieldError\n                    errors={field.state.meta.errors.map((error) =>\n                      typeof error === \"string\" ? { message: error } : error,\n                    )}\n                  />\n                )}\n              </Field>\n            );\n          }}\n        </form.Field>\n      </FieldGroup>\n      <Button type=\"submit\">Submit</Button>\n    </form>\n  );\n}\n\n/**\n * Building forms with TanStack Form and Zod.\n */\nconst meta: Meta<typeof TanStackFormProfileForm> = {\n  title: \"ui/base/Form (TanStack Form)\",\n  component: TanStackFormProfileForm,\n  tags: [\"autodocs\"],\n  argTypes: {},\n} satisfies Meta<typeof TanStackFormProfileForm>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the form.\n */\nexport const Default: Story = {};\n\nexport const ShouldSucceedWhenValidInput: Story = {\n  name: \"when typing a valid username, should not show an error message\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvas, step }) => {\n    await step(\"Type a valid username\", async () => {\n      await userEvent.type(\n        await canvas.findByRole(\"textbox\", { name: /username/i }),\n        \"mockuser\",\n      );\n    });\n\n    await step(\"Click the submit button\", async () => {\n      await userEvent.click(\n        await canvas.findByRole(\"button\", { name: /submit/i }),\n      );\n      expect(\n        await canvas.queryByText(/username must be at least 6 characters/i, {\n          exact: true,\n        }),\n      ).toBeNull();\n    });\n  },\n};\n\nexport const ShouldShowErrorWhenInvalidInput: Story = {\n  name: \"when typing a short username, should show an error message\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvas, step }) => {\n    await step(\"Type a short username\", async () => {\n      await userEvent.type(\n        await canvas.findByRole(\"textbox\", { name: /username/i }),\n        \"fail\",\n      );\n    });\n\n    await step(\"Click the submit button\", async () => {\n      await userEvent.click(\n        await canvas.findByRole(\"button\", { name: /submit/i }),\n      );\n      expect(\n        await canvas.queryByText(/username must be at least 6 characters/i, {\n          exact: true,\n        }),\n      ).toBeVisible();\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/hover-card-story/hover-card-base.stories.tsx",
      "content": "import { expect, userEvent, waitFor, within } from \"storybook/test\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  HoverCard,\n  HoverCardContent,\n  HoverCardTrigger,\n} from \"@/components/ui/hover-card\";\n\n/**\n * For sighted users to preview content available behind a link.\n */\nconst meta = {\n  title: \"ui/base/HoverCard\",\n  component: HoverCard,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {},\n  render: (args) => (\n    <HoverCard {...args}>\n      <HoverCardTrigger>Hover</HoverCardTrigger>\n      <HoverCardContent>\n        The React Framework - created and maintained by @vercel.\n      </HoverCardContent>\n    </HoverCard>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof HoverCard>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the hover card.\n */\nexport const Default: Story = {};\n\n/**\n * Use the `delay` and `closeDelay` props to control the delay before the\n * hover card opens and closes.\n */\nexport const Instant: Story = {\n  render: (args) => (\n    <HoverCard {...args}>\n      <HoverCardTrigger delay={0} closeDelay={0}>\n        Hover\n      </HoverCardTrigger>\n      <HoverCardContent>\n        The React Framework - created and maintained by @vercel.\n      </HoverCardContent>\n    </HoverCard>\n  ),\n};\n\nexport const ShouldShowOnHover: Story = {\n  name: \"when hovering over trigger, should show hover card content\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n\n    await step(\"Hover over the trigger element\", async () => {\n      await userEvent.hover(await canvasBody.findByText(/hover/i));\n      await waitFor(() =>\n        expect(\n          canvasElement.ownerDocument.body.querySelector(\n            \"[data-slot=hover-card-content]\",\n          ),\n        ).toBeVisible(),\n      );\n    });\n    await step(\"Unhover the trigger element\", async () => {\n      await userEvent.unhover(await canvasBody.findByText(/hover/i));\n      await waitFor(() =>\n        expect(\n          canvasElement.ownerDocument.body.querySelector(\n            \"[data-slot=hover-card-content]\",\n          ),\n        ).toBeNull(),\n      );\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/input-story/input-base.stories.tsx",
      "content": "import { expect, userEvent } from \"storybook/test\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\n\n/**\n * Displays a form input field or a component that looks like an input field.\n */\nconst meta = {\n  title: \"ui/base/Input\",\n  component: Input,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {\n    className: \"w-96\",\n    type: \"email\",\n    placeholder: \"Email\",\n    disabled: false,\n  },\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Input>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the input field.\n */\nexport const Default: Story = {};\n\n/**\n * Use the `disabled` prop to make the input non-interactive and appears faded,\n * indicating that input is not currently accepted.\n */\nexport const Disabled: Story = {\n  args: { disabled: true },\n};\n\n/**\n * Use the `Label` component to includes a clear, descriptive label above or\n * alongside the input area to guide users.\n */\nexport const WithLabel: Story = {\n  render: (args) => (\n    <div className=\"grid items-center gap-1.5\">\n      <Label htmlFor=\"email\">{args.placeholder}</Label>\n      <Input {...args} id=\"email\" />\n    </div>\n  ),\n};\n\n/**\n * Use a text element below the input field to provide additional instructions\n * or information to users.\n */\nexport const WithHelperText: Story = {\n  render: (args) => (\n    <div className=\"grid items-center gap-1.5\">\n      <Label htmlFor=\"email-2\">{args.placeholder}</Label>\n      <Input {...args} id=\"email-2\" />\n      <p className=\"text-foreground/60 text-sm\">Enter your email address.</p>\n    </div>\n  ),\n};\n\n/**\n * Use the `Button` component to indicate that the input field can be submitted\n * or used to trigger an action.\n */\nexport const WithButton: Story = {\n  render: (args) => (\n    <div className=\"flex items-center space-x-2\">\n      <Input {...args} />\n      <Button type=\"submit\">Subscribe</Button>\n    </div>\n  ),\n};\n\nexport const ShouldEnterText: Story = {\n  name: \"when user enters text, should see it in the input field\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvas, step }) => {\n    const input = await canvas.findByPlaceholderText(/email/i);\n    const mockedInput = \"mocked@shadcn.com\";\n\n    await step(\"focus and type into the input field\", async () => {\n      await userEvent.click(input);\n      await userEvent.type(input, mockedInput);\n    });\n\n    expect(input).toHaveValue(mockedInput);\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/input-group-story/input-group-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport {\n  Check,\n  CheckIcon,\n  ChevronDownIcon,\n  Code,\n  Copy,\n  CornerDownLeft,\n  CreditCardIcon,\n  HelpCircle,\n  Info,\n  InfoIcon,\n  Link2Icon,\n  LoaderIcon,\n  MailIcon,\n  MoreHorizontal,\n  RefreshCcw,\n  SearchIcon,\n  Star,\n  StarIcon,\n} from \"lucide-react\";\nimport * as React from \"react\";\n\nimport {\n  ButtonGroup,\n  ButtonGroupText,\n} from \"@/components/ui/button-group\";\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport {\n  InputGroup,\n  InputGroupAddon,\n  InputGroupButton,\n  InputGroupInput,\n  InputGroupText,\n  InputGroupTextarea,\n} from \"@/components/ui/input-group\";\nimport { Label } from \"@/components/ui/label\";\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger,\n} from \"@/components/ui/popover\";\nimport { Spinner } from \"@/components/ui/spinner\";\nimport {\n  Tooltip,\n  TooltipContent,\n  TooltipProvider,\n  TooltipTrigger,\n} from \"@/components/ui/tooltip\";\n\n/**\n * Display additional information or actions to an input or textarea.\n */\nconst meta: Meta<typeof InputGroup> = {\n  title: \"ui/base/InputGroup\",\n  component: InputGroup,\n  tags: [\"autodocs\"],\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof InputGroup>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * Input groups with icon addons for visual enhancement.\n */\nexport const WithIcons: Story = {\n  render: (args) => (\n    <div className=\"grid w-full max-w-sm gap-6\">\n      <InputGroup {...args}>\n        <InputGroupInput placeholder=\"Search...\" />\n        <InputGroupAddon>\n          <SearchIcon />\n        </InputGroupAddon>\n      </InputGroup>\n      <InputGroup {...args}>\n        <InputGroupInput type=\"email\" placeholder=\"Enter your email\" />\n        <InputGroupAddon>\n          <MailIcon />\n        </InputGroupAddon>\n      </InputGroup>\n      <InputGroup {...args}>\n        <InputGroupInput placeholder=\"Card number\" />\n        <InputGroupAddon>\n          <CreditCardIcon />\n        </InputGroupAddon>\n        <InputGroupAddon align=\"inline-end\">\n          <CheckIcon />\n        </InputGroupAddon>\n      </InputGroup>\n      <InputGroup {...args}>\n        <InputGroupInput placeholder=\"Card number\" />\n        <InputGroupAddon align=\"inline-end\">\n          <StarIcon />\n          <InfoIcon />\n        </InputGroupAddon>\n      </InputGroup>\n    </div>\n  ),\n};\n\n/**\n * Display additional text information alongside inputs.\n */\nexport const WithText: Story = {\n  render: (args) => (\n    <div className=\"grid w-full max-w-sm gap-6\">\n      <InputGroup {...args}>\n        <InputGroupAddon>\n          <InputGroupText>$</InputGroupText>\n        </InputGroupAddon>\n        <InputGroupInput placeholder=\"0.00\" />\n        <InputGroupAddon align=\"inline-end\">\n          <InputGroupText>USD</InputGroupText>\n        </InputGroupAddon>\n      </InputGroup>\n      <InputGroup {...args}>\n        <InputGroupAddon>\n          <InputGroupText>https://</InputGroupText>\n        </InputGroupAddon>\n        <InputGroupInput placeholder=\"example.com\" className=\"!pl-0.5\" />\n        <InputGroupAddon align=\"inline-end\">\n          <InputGroupText>.com</InputGroupText>\n        </InputGroupAddon>\n      </InputGroup>\n      <InputGroup {...args}>\n        <InputGroupInput placeholder=\"Enter your username\" />\n        <InputGroupAddon align=\"inline-end\">\n          <InputGroupText>@company.com</InputGroupText>\n        </InputGroupAddon>\n      </InputGroup>\n      <InputGroup {...args}>\n        <InputGroupTextarea placeholder=\"Enter your message\" />\n        <InputGroupAddon align=\"block-end\">\n          <InputGroupText className=\"text-muted-foreground text-xs\">\n            120 characters left\n          </InputGroupText>\n        </InputGroupAddon>\n      </InputGroup>\n    </div>\n  ),\n};\n\n/**\n * Add buttons to perform actions within the input group.\n */\nexport const WithButtons: Story = {\n  render: (args) => {\n    const [isCopied, setIsCopied] = React.useState(false);\n    const [isFavorite, setIsFavorite] = React.useState(false);\n\n    const copyToClipboard = (text: string) => {\n      navigator.clipboard.writeText(text);\n      setIsCopied(true);\n      setTimeout(() => setIsCopied(false), 2000);\n    };\n\n    return (\n      <div className=\"grid w-full max-w-sm gap-6\">\n        <InputGroup {...args}>\n          <InputGroupInput placeholder=\"https://x.com/shadcn\" readOnly />\n          <InputGroupAddon align=\"inline-end\">\n            <InputGroupButton\n              aria-label=\"Copy\"\n              title=\"Copy\"\n              size=\"icon-xs\"\n              nativeButton\n              onClick={() => {\n                copyToClipboard(\"https://x.com/shadcn\");\n              }}\n            >\n              {isCopied ? <Check /> : <Copy />}\n            </InputGroupButton>\n          </InputGroupAddon>\n        </InputGroup>\n        <InputGroup className=\"[--radius:9999px]\">\n          <Popover>\n            <InputGroupAddon>\n              <PopoverTrigger\n                nativeButton\n                render={\n                  <InputGroupButton\n                    variant=\"secondary\"\n                    size=\"icon-xs\"\n                    nativeButton\n                  />\n                }\n              >\n                <Info />\n              </PopoverTrigger>\n            </InputGroupAddon>\n            <PopoverContent\n              align=\"start\"\n              className=\"flex flex-col gap-1 rounded-xl text-sm\"\n            >\n              <p className=\"font-medium\">Your connection is not secure.</p>\n              <p>\n                You should not enter any sensitive information on this site.\n              </p>\n            </PopoverContent>\n          </Popover>\n          <InputGroupAddon className=\"text-muted-foreground pl-1.5\">\n            https://\n          </InputGroupAddon>\n          <InputGroupInput id=\"input-secure-19\" />\n          <InputGroupAddon align=\"inline-end\">\n            <InputGroupButton\n              onClick={() => setIsFavorite(!isFavorite)}\n              size=\"icon-xs\"\n              nativeButton\n            >\n              <Star\n                data-favorite={isFavorite}\n                className=\"data-[favorite=true]:fill-blue-600 data-[favorite=true]:stroke-blue-600\"\n              />\n            </InputGroupButton>\n          </InputGroupAddon>\n        </InputGroup>\n        <InputGroup {...args}>\n          <InputGroupInput placeholder=\"Type to search...\" />\n          <InputGroupAddon align=\"inline-end\">\n            <InputGroupButton variant=\"secondary\" nativeButton>\n              Search\n            </InputGroupButton>\n          </InputGroupAddon>\n        </InputGroup>\n      </div>\n    );\n  },\n};\n\n/**\n * Add tooltips to provide additional context or help.\n */\nexport const WithTooltips: Story = {\n  render: (args) => (\n    <div className=\"grid w-full max-w-sm gap-4\">\n      <TooltipProvider>\n        <InputGroup {...args}>\n          <InputGroupInput placeholder=\"Enter password\" type=\"password\" />\n          <InputGroupAddon align=\"inline-end\">\n            <Tooltip>\n              <InputGroupButton\n                render={<TooltipTrigger />}\n                variant=\"ghost\"\n                aria-label=\"Info\"\n                size=\"icon-xs\"\n              >\n                <InfoIcon />\n              </InputGroupButton>\n              <TooltipContent>\n                <p>Password must be at least 8 characters</p>\n              </TooltipContent>\n            </Tooltip>\n          </InputGroupAddon>\n        </InputGroup>\n        <InputGroup {...args}>\n          <InputGroupInput placeholder=\"Your email address\" />\n          <InputGroupAddon align=\"inline-end\">\n            <Tooltip>\n              <InputGroupButton\n                render={<TooltipTrigger />}\n                variant=\"ghost\"\n                aria-label=\"Help\"\n                size=\"icon-xs\"\n              >\n                <HelpCircle />\n              </InputGroupButton>\n              <TooltipContent>\n                <p>We'll use this to send you notifications</p>\n              </TooltipContent>\n            </Tooltip>\n          </InputGroupAddon>\n        </InputGroup>\n        <InputGroup {...args}>\n          <InputGroupInput placeholder=\"Enter API key\" />\n          <Tooltip>\n            <TooltipTrigger render={<InputGroupAddon />}>\n              <InputGroupButton\n                variant=\"ghost\"\n                aria-label=\"Help\"\n                size=\"icon-xs\"\n              >\n                <HelpCircle />\n              </InputGroupButton>\n            </TooltipTrigger>\n            <TooltipContent side=\"left\">\n              <p>Click for help with API keys</p>\n            </TooltipContent>\n          </Tooltip>\n        </InputGroup>\n      </TooltipProvider>\n    </div>\n  ),\n};\n\n/**\n * Input groups also work with textarea components.\n */\nexport const WithTextarea: Story = {\n  render: (args) => {\n    return (\n      <div className=\"grid w-full max-w-md gap-4\">\n        <InputGroup {...args}>\n          <InputGroupTextarea\n            id=\"textarea-code-32\"\n            placeholder=\"console.log('Hello, world!');\"\n            className=\"min-h-[200px]\"\n          />\n          <InputGroupAddon align=\"block-end\" className=\"border-t\">\n            <InputGroupText>Line 1, Column 1</InputGroupText>\n            <InputGroupButton size=\"sm\" className=\"ml-auto\" variant=\"default\">\n              Run <CornerDownLeft />\n            </InputGroupButton>\n          </InputGroupAddon>\n          <InputGroupAddon align=\"block-start\" className=\"border-b\">\n            <InputGroupText className=\"font-mono font-medium\">\n              <Code />\n              script.js\n            </InputGroupText>\n            <InputGroupButton className=\"ml-auto\" size=\"icon-xs\">\n              <RefreshCcw />\n            </InputGroupButton>\n            <InputGroupButton variant=\"ghost\" size=\"icon-xs\">\n              <Copy />\n            </InputGroupButton>\n          </InputGroupAddon>\n        </InputGroup>\n      </div>\n    );\n  },\n};\n\n/**\n * Show loading indicators while processing input.\n */\nexport const WithSpinner: Story = {\n  render: (args) => (\n    <div className=\"grid w-full max-w-sm gap-4\">\n      <InputGroup {...args} data-disabled>\n        <InputGroupInput placeholder=\"Searching...\" disabled />\n        <InputGroupAddon align=\"inline-end\">\n          <Spinner />\n        </InputGroupAddon>\n      </InputGroup>\n      <InputGroup data-disabled>\n        <InputGroupInput placeholder=\"Processing...\" disabled />\n        <InputGroupAddon>\n          <Spinner />\n        </InputGroupAddon>\n      </InputGroup>\n      <InputGroup data-disabled>\n        <InputGroupInput placeholder=\"Saving changes...\" disabled />\n        <InputGroupAddon align=\"inline-end\">\n          <InputGroupText>Saving...</InputGroupText>\n          <Spinner />\n        </InputGroupAddon>\n      </InputGroup>\n      <InputGroup data-disabled>\n        <InputGroupInput placeholder=\"Refreshing data...\" disabled />\n        <InputGroupAddon>\n          <LoaderIcon className=\"animate-spin\" />\n        </InputGroupAddon>\n        <InputGroupAddon align=\"inline-end\">\n          <InputGroupText className=\"text-muted-foreground\">\n            Please wait...\n          </InputGroupText>\n        </InputGroupAddon>\n      </InputGroup>\n    </div>\n  ),\n};\n\n/**\n * Add labels within input groups to improve accessibility.\n */\nexport const WithLabels: Story = {\n  render: (args) => (\n    <div className=\"grid w-full max-w-sm gap-4\">\n      <TooltipProvider>\n        <InputGroup {...args}>\n          <InputGroupInput id=\"email\" placeholder=\"shadcn\" />\n          <InputGroupAddon>\n            <Label htmlFor=\"email\">@</Label>\n          </InputGroupAddon>\n        </InputGroup>\n        <InputGroup {...args}>\n          <InputGroupInput id=\"email-2\" placeholder=\"shadcn@vercel.com\" />\n          <InputGroupAddon align=\"block-start\">\n            <Label htmlFor=\"email-2\" className=\"text-foreground\">\n              Email\n            </Label>\n            <Tooltip>\n              <InputGroupButton\n                render={<TooltipTrigger />}\n                variant=\"ghost\"\n                aria-label=\"Help\"\n                className=\"ml-auto rounded-full\"\n                size=\"icon-xs\"\n              >\n                <InfoIcon />\n              </InputGroupButton>\n              <TooltipContent>\n                <p>We'll use this to send you notifications</p>\n              </TooltipContent>\n            </Tooltip>\n          </InputGroupAddon>\n        </InputGroup>\n      </TooltipProvider>\n    </div>\n  ),\n};\n\n/**\n * Pair input groups with dropdown menus for complex interactions.\n */\nexport const WithDropdowns: Story = {\n  render: (args) => (\n    <div className=\"grid w-full max-w-sm gap-4\">\n      <InputGroup {...args}>\n        <InputGroupInput placeholder=\"Enter file name\" />\n        <InputGroupAddon align=\"inline-end\">\n          <DropdownMenu>\n            <DropdownMenuTrigger\n              render={\n                <InputGroupButton\n                  variant=\"ghost\"\n                  aria-label=\"More\"\n                  size=\"icon-xs\"\n                />\n              }\n            >\n              <MoreHorizontal />\n            </DropdownMenuTrigger>\n            <DropdownMenuContent align=\"end\">\n              <DropdownMenuItem>Settings</DropdownMenuItem>\n              <DropdownMenuItem>Copy path</DropdownMenuItem>\n              <DropdownMenuItem>Open location</DropdownMenuItem>\n            </DropdownMenuContent>\n          </DropdownMenu>\n        </InputGroupAddon>\n      </InputGroup>\n      <InputGroup className=\"[--radius:1rem]\">\n        <InputGroupInput placeholder=\"Enter search query\" />\n        <InputGroupAddon align=\"inline-end\">\n          <DropdownMenu>\n            <DropdownMenuTrigger\n              render={\n                <InputGroupButton variant=\"ghost\" className=\"!pr-1.5 text-xs\" />\n              }\n            >\n              Search In... <ChevronDownIcon className=\"size-3\" />\n            </DropdownMenuTrigger>\n            <DropdownMenuContent align=\"end\" className=\"[--radius:0.95rem]\">\n              <DropdownMenuItem>Documentation</DropdownMenuItem>\n              <DropdownMenuItem>Blog Posts</DropdownMenuItem>\n              <DropdownMenuItem>Changelog</DropdownMenuItem>\n            </DropdownMenuContent>\n          </DropdownMenu>\n        </InputGroupAddon>\n      </InputGroup>\n    </div>\n  ),\n};\n\n/**\n * Wrap input groups with button groups to create prefixes and suffixes.\n */\nexport const WithButtonGroup: Story = {\n  render: (args) => (\n    <div className=\"grid w-full max-w-sm gap-6\">\n      <ButtonGroup>\n        <ButtonGroupText render={<Label htmlFor=\"url\" />}>\n          https://\n        </ButtonGroupText>\n        <InputGroup {...args}>\n          <InputGroupInput id=\"url\" />\n          <InputGroupAddon align=\"inline-end\">\n            <Link2Icon />\n          </InputGroupAddon>\n        </InputGroup>\n        <ButtonGroupText>.com</ButtonGroupText>\n      </ButtonGroup>\n    </div>\n  ),\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/input-otp-story/input-otp-base.stories.tsx",
      "content": "import { expect, fn, userEvent } from \"storybook/test\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport { REGEXP_ONLY_DIGITS, REGEXP_ONLY_DIGITS_AND_CHARS } from \"input-otp\";\n\nimport {\n  InputOTP,\n  InputOTPGroup,\n  InputOTPSeparator,\n  InputOTPSlot,\n} from \"@/components/ui/input-otp\";\n\n/**\n * Accessible one-time password component with copy paste functionality.\n */\nconst meta = {\n  title: \"ui/base/InputOTP\",\n  component: InputOTP,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {\n    maxLength: 6,\n    onChange: fn(),\n    onComplete: fn(),\n    pattern: REGEXP_ONLY_DIGITS_AND_CHARS,\n    children: null,\n    \"aria-label\": \"One-time password\",\n  },\n\n  render: (args) => (\n    <InputOTP {...args} render={undefined}>\n      <InputOTPGroup>\n        <InputOTPSlot index={0} />\n        <InputOTPSlot index={1} />\n        <InputOTPSlot index={2} />\n        <InputOTPSlot index={3} />\n        <InputOTPSlot index={4} />\n        <InputOTPSlot index={5} />\n      </InputOTPGroup>\n    </InputOTP>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof InputOTP>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the InputOTP field.\n */\nexport const Default: Story = {};\n\n/**\n * The number form of the InputOTP field.\n */\nexport const OnlyNumbers: Story = {\n  args: {\n    pattern: REGEXP_ONLY_DIGITS,\n  },\n};\n\n/**\n * Use multiple groups to separate the input slots.\n */\nexport const SeparatedGroup: Story = {\n  render: (args) => (\n    <InputOTP {...args} render={undefined}>\n      <InputOTPGroup>\n        <InputOTPSlot index={0} />\n        <InputOTPSlot index={1} />\n        <InputOTPSlot index={2} />\n      </InputOTPGroup>\n      <InputOTPSeparator />\n      <InputOTPGroup>\n        <InputOTPSlot index={3} />\n        <InputOTPSlot index={4} />\n        <InputOTPSlot index={5} />\n      </InputOTPGroup>\n    </InputOTP>\n  ),\n};\n\nexport const ShouldAcceptTextWhenTyping: Story = {\n  name: \"when typing text, should call onChange and onComplete\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ args, canvas, step }) => {\n    const inputTextbox = await canvas.findByRole(\"textbox\");\n\n    await step(\"type into input textbox\", async () => {\n      await userEvent.click(inputTextbox);\n      await userEvent.type(inputTextbox, \"mocked\");\n      expect(args.onChange).toHaveBeenCalledTimes(6);\n    });\n\n    await step(\"finish typing by pressing Enter\", async () => {\n      await userEvent.keyboard(\"{enter}\");\n      expect(args.onComplete).toHaveBeenCalledTimes(1);\n    });\n  },\n};\n\nexport const ShouldAcceptOnlyNumbersWhenRestricted: Story = {\n  ...OnlyNumbers,\n  name: \"when only numbers are allowed, should call onChange for numbers and onComplete\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ args, canvas, step }) => {\n    const inputTextbox = await canvas.findByRole(\"textbox\");\n\n    await step(\"type text into input textbox\", async () => {\n      await userEvent.click(inputTextbox);\n      await userEvent.type(inputTextbox, \"mocked\");\n      expect(args.onChange).toHaveBeenCalledTimes(0);\n    });\n\n    await step(\"type numbers into input textbox\", async () => {\n      await userEvent.type(inputTextbox, \"123456\");\n      expect(args.onChange).toHaveBeenCalledTimes(6);\n    });\n\n    await step(\"finish typing by pressing Enter\", async () => {\n      await userEvent.keyboard(\"{enter}\");\n      expect(args.onComplete).toHaveBeenCalledTimes(1);\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/label-story/label-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport { Label } from \"@/components/ui/label\";\n\n/**\n * Renders an accessible label associated with controls.\n */\nconst meta = {\n  title: \"ui/base/Label\",\n  component: Label,\n  tags: [\"autodocs\"],\n  argTypes: {\n    children: {\n      control: { type: \"text\" },\n    },\n  },\n  args: {\n    children: \"Your email address\",\n    htmlFor: \"email\",\n  },\n} satisfies Meta<typeof Label>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof Label>;\n\n/**\n * The default form of the label.\n */\nexport const Default: Story = {};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/menubar-story/menubar-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  Menubar,\n  MenubarCheckboxItem,\n  MenubarContent,\n  MenubarGroup,\n  MenubarItem,\n  MenubarLabel,\n  MenubarMenu,\n  MenubarRadioGroup,\n  MenubarRadioItem,\n  MenubarSeparator,\n  MenubarShortcut,\n  MenubarSub,\n  MenubarSubContent,\n  MenubarSubTrigger,\n  MenubarTrigger,\n} from \"@/components/ui/menubar\";\nimport { expect, userEvent, within } from \"storybook/test\";\n\n/**\n * A visually persistent menu common in desktop applications that provides\n * quick access to a consistent set of commands.\n */\nconst meta = {\n  title: \"ui/base/Menubar\",\n  component: Menubar,\n  tags: [\"autodocs\"],\n  argTypes: {},\n\n  render: (args) => (\n    <Menubar {...args}>\n      <MenubarMenu>\n        <MenubarTrigger>File</MenubarTrigger>\n        <MenubarContent>\n          <MenubarItem>\n            New Tab <MenubarShortcut>⌘T</MenubarShortcut>\n          </MenubarItem>\n          <MenubarItem>New Window</MenubarItem>\n          <MenubarSeparator />\n          <MenubarItem disabled>Share</MenubarItem>\n          <MenubarSeparator />\n          <MenubarItem>Print</MenubarItem>\n        </MenubarContent>\n      </MenubarMenu>\n    </Menubar>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Menubar>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the menubar.\n */\nexport const Default: Story = {};\n\n/**\n * A menubar with a submenu.\n */\nexport const WithSubmenu: Story = {\n  render: (args) => (\n    <Menubar {...args}>\n      <MenubarMenu>\n        <MenubarTrigger>Actions</MenubarTrigger>\n        <MenubarContent>\n          <MenubarItem>Download</MenubarItem>\n          <MenubarSub>\n            <MenubarSubTrigger>Share</MenubarSubTrigger>\n            <MenubarSubContent>\n              <MenubarItem>Email link</MenubarItem>\n              <MenubarItem>Messages</MenubarItem>\n              <MenubarItem>Notes</MenubarItem>\n            </MenubarSubContent>\n          </MenubarSub>\n        </MenubarContent>\n      </MenubarMenu>\n    </Menubar>\n  ),\n};\n\n/**\n * A menubar with radio items.\n */\nexport const WithRadioItems: Story = {\n  render: (args) => (\n    <Menubar {...args}>\n      <MenubarMenu>\n        <MenubarTrigger>View</MenubarTrigger>\n        <MenubarContent>\n          <MenubarLabel inset>Device Size</MenubarLabel>\n          <MenubarRadioGroup value=\"md\">\n            <MenubarRadioItem value=\"sm\">Small</MenubarRadioItem>\n            <MenubarRadioItem value=\"md\">Medium</MenubarRadioItem>\n            <MenubarRadioItem value=\"lg\">Large</MenubarRadioItem>\n          </MenubarRadioGroup>\n        </MenubarContent>\n      </MenubarMenu>\n    </Menubar>\n  ),\n};\n\n/**\n * A menubar with checkbox items.\n */\nexport const WithCheckboxItems: Story = {\n  render: (args) => (\n    <Menubar {...args}>\n      <MenubarMenu>\n        <MenubarTrigger>Filters</MenubarTrigger>\n        <MenubarContent>\n          <MenubarItem>Show All</MenubarItem>\n          <MenubarGroup>\n            <MenubarCheckboxItem checked>Unread</MenubarCheckboxItem>\n            <MenubarCheckboxItem checked>Important</MenubarCheckboxItem>\n            <MenubarCheckboxItem>Flagged</MenubarCheckboxItem>\n          </MenubarGroup>\n        </MenubarContent>\n      </MenubarMenu>\n    </Menubar>\n  ),\n};\n\nexport const ShouldOpenClose: Story = {\n  name: \"when clicking an item, should close the menubar\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n\n    await step(\"open the menubar\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"menuitem\", { name: /file/i }),\n      );\n      expect(await canvasBody.findByRole(\"menu\")).toBeInTheDocument();\n    });\n\n    const items = await canvasBody.findAllByRole(\"menuitem\");\n    expect(items).toHaveLength(5);\n\n    await step(\"click the first item to close the menubar\", async () => {\n      await userEvent.click(items[0], { delay: 100 });\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/navigation-menu-story/navigation-menu-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  NavigationMenu,\n  NavigationMenuContent,\n  NavigationMenuItem,\n  NavigationMenuLink,\n  NavigationMenuList,\n  NavigationMenuTrigger,\n  navigationMenuTriggerStyle,\n} from \"@/components/ui/navigation-menu\";\n\n/**\n * A collection of links for navigating websites.\n */\nconst meta = {\n  title: \"ui/base/NavigationMenu\",\n  component: NavigationMenu,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  render: (args) => (\n    <NavigationMenu {...args}>\n      <NavigationMenuList>\n        <NavigationMenuItem>\n          <NavigationMenuLink className={navigationMenuTriggerStyle()}>\n            Overview\n          </NavigationMenuLink>\n        </NavigationMenuItem>\n        <NavigationMenuList>\n          <NavigationMenuItem>\n            <NavigationMenuTrigger className={navigationMenuTriggerStyle()}>\n              Documentation\n            </NavigationMenuTrigger>\n            <NavigationMenuContent>\n              <ul className=\"grid w-96 p-2\">\n                <li>\n                  <NavigationMenuLink className={navigationMenuTriggerStyle()}>\n                    API Reference\n                  </NavigationMenuLink>\n                </li>\n                <li>\n                  <NavigationMenuLink className={navigationMenuTriggerStyle()}>\n                    Getting Started\n                  </NavigationMenuLink>\n                </li>\n                <li>\n                  <NavigationMenuLink className={navigationMenuTriggerStyle()}>\n                    Guides\n                  </NavigationMenuLink>\n                </li>\n              </ul>\n            </NavigationMenuContent>\n          </NavigationMenuItem>\n        </NavigationMenuList>\n        <NavigationMenuItem>\n          <NavigationMenuLink\n            className={navigationMenuTriggerStyle()}\n            href=\"https:www.google.com\"\n            target=\"_blank\"\n          >\n            External\n          </NavigationMenuLink>\n        </NavigationMenuItem>\n      </NavigationMenuList>\n    </NavigationMenu>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof NavigationMenu>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the navigation menu.\n */\nexport const Default: Story = {};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/pagination-story/pagination-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  Pagination,\n  PaginationContent,\n  PaginationEllipsis,\n  PaginationItem,\n  PaginationLink,\n  PaginationNext,\n  PaginationPrevious,\n} from \"@/components/ui/pagination\";\n\n/**\n * Pagination with page navigation, next and previous links.\n */\nconst meta = {\n  title: \"ui/base/Pagination\",\n  component: Pagination,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  render: (args) => (\n    <Pagination {...args}>\n      <PaginationContent>\n        <PaginationItem>\n          <PaginationPrevious href=\"#\" />\n        </PaginationItem>\n        <PaginationItem>\n          <PaginationLink href=\"#\">1</PaginationLink>\n        </PaginationItem>\n        <PaginationItem>\n          <PaginationLink href=\"#\">2</PaginationLink>\n        </PaginationItem>\n        <PaginationItem>\n          <PaginationLink href=\"#\">3</PaginationLink>\n        </PaginationItem>\n        <PaginationItem>\n          <PaginationEllipsis />\n        </PaginationItem>\n        <PaginationItem>\n          <PaginationNext href=\"#\" />\n        </PaginationItem>\n      </PaginationContent>\n    </Pagination>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Pagination>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the pagination.\n */\nexport const Default: Story = {};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/popover-story/popover-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger,\n} from \"@/components/ui/popover\";\nimport { expect, userEvent, waitFor, within } from \"storybook/test\";\n\n/**\n * Displays rich content in a portal, triggered by a button.\n */\nconst meta = {\n  title: \"ui/base/Popover\",\n  component: Popover,\n  tags: [\"autodocs\"],\n  argTypes: {},\n\n  render: (args) => (\n    <Popover {...args}>\n      <PopoverTrigger>Open</PopoverTrigger>\n      <PopoverContent>Place content for the popover here.</PopoverContent>\n    </Popover>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Popover>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the popover.\n */\nexport const Default: Story = {};\n\nexport const ShouldOpenClose: Story = {\n  name: \"when clicking the trigger, should open and close the popover\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n\n    await step(\"click the trigger to open the popover\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /open/i }),\n      );\n      expect(await canvasBody.findByRole(\"dialog\")).toBeInTheDocument();\n    });\n\n    await step(\"click the trigger to close the popover\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /open/i }),\n      );\n      await waitFor(() => {\n        expect(canvasBody.queryByRole(\"dialog\")).not.toBeInTheDocument();\n      });\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/progress-story/progress-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport { Progress } from \"@/components/ui/progress\";\n\n/**\n * Displays an indicator showing the completion progress of a task, typically\n * displayed as a progress bar.\n */\nconst meta = {\n  title: \"ui/base/Progress\",\n  component: Progress,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {\n    \"aria-label\": \"Progress\",\n    value: 30,\n    max: 100,\n  },\n} satisfies Meta<typeof Progress>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the progress.\n */\nexport const Default: Story = {};\n\n/**\n * When the progress is indeterminate.\n */\nexport const Indeterminate: Story = {\n  args: {\n    value: undefined,\n  },\n};\n\n/**\n * When the progress is completed.\n */\nexport const Completed: Story = {\n  args: {\n    value: 100,\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/radio-group-story/radio-group-base.stories.tsx",
      "content": "import { expect, userEvent, waitFor } from \"storybook/test\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport { Label } from \"@/components/ui/label\";\nimport {\n  RadioGroup,\n  RadioGroupItem,\n} from \"@/components/ui/radio-group\";\n\n/**\n * A set of checkable buttons—known as radio buttons—where no more than one of\n * the buttons can be checked at a time.\n */\nconst meta = {\n  title: \"ui/base/RadioGroup\",\n  component: RadioGroup,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {\n    defaultValue: \"comfortable\",\n    className: \"grid gap-2 grid-cols-[1rem_1fr] items-center\",\n  },\n  render: (args) => (\n    <RadioGroup {...args}>\n      <RadioGroupItem value=\"default\" id=\"r1\" />\n      <Label htmlFor=\"r1\">Default</Label>\n      <RadioGroupItem value=\"comfortable\" id=\"r2\" />\n      <Label htmlFor=\"r2\">Comfortable</Label>\n      <RadioGroupItem value=\"compact\" id=\"r3\" />\n      <Label htmlFor=\"r3\">Compact</Label>\n    </RadioGroup>\n  ),\n} satisfies Meta<typeof RadioGroup>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the radio group.\n */\nexport const Default: Story = {};\n\nexport const ShouldToggleRadio: Story = {\n  name: \"when clicking on a radio button, it should toggle its state\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvas, step }) => {\n    const radios = await canvas.findAllByRole(\"radio\");\n    expect(radios).toHaveLength(3);\n\n    await step(\"click the default radio button\", async () => {\n      await userEvent.click(radios[0]);\n      await waitFor(() => expect(radios[0]).toBeChecked());\n      await waitFor(() => expect(radios[1]).not.toBeChecked());\n    });\n\n    await step(\"click the comfortable radio button\", async () => {\n      await userEvent.click(radios[1]);\n      await waitFor(() => expect(radios[1]).toBeChecked());\n      await waitFor(() => expect(radios[0]).not.toBeChecked());\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/resizable-story/resizable-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  ResizableHandle,\n  ResizablePanel,\n  ResizablePanelGroup,\n} from \"@/components/ui/resizable\";\nimport { fn } from \"storybook/test\";\n/**\n * Accessible resizable panel groups and layouts with keyboard support.\n */\nconst meta: Meta<typeof ResizablePanelGroup> = {\n  title: \"ui/base/ResizablePanelGroup\",\n  component: ResizablePanelGroup,\n  tags: [\"autodocs\"],\n  argTypes: {\n    onLayoutChange: {\n      control: false,\n    },\n  },\n  args: {\n    onLayoutChange: fn(),\n    className: \"max-w-96 rounded-lg border\",\n    orientation: \"horizontal\",\n  },\n  render: (args) => (\n    <ResizablePanelGroup {...args}>\n      <ResizablePanel defaultSize={50}>\n        <div className=\"flex h-[200px] items-center justify-center p-6\">\n          <span className=\"font-semibold\">One</span>\n        </div>\n      </ResizablePanel>\n      <ResizableHandle />\n      <ResizablePanel defaultSize={50}>\n        <ResizablePanelGroup orientation=\"vertical\">\n          <ResizablePanel defaultSize={25}>\n            <div className=\"flex h-full items-center justify-center p-6\">\n              <span className=\"font-semibold\">Two</span>\n            </div>\n          </ResizablePanel>\n          <ResizableHandle />\n          <ResizablePanel defaultSize={75}>\n            <div className=\"flex h-full items-center justify-center p-6\">\n              <span className=\"font-semibold\">Three</span>\n            </div>\n          </ResizablePanel>\n        </ResizablePanelGroup>\n      </ResizablePanel>\n    </ResizablePanelGroup>\n  ),\n} satisfies Meta<typeof ResizablePanelGroup>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the resizable panel group.\n */\nexport const Default: Story = {};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/scroll-area-story/scroll-area-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport { ScrollArea } from \"@/components/ui/scroll-area\";\n\n/**\n * Augments native scroll functionality for custom, cross-browser styling.\n */\nconst meta = {\n  title: \"ui/base/ScrollArea\",\n  component: ScrollArea,\n  tags: [\"autodocs\"],\n  argTypes: {\n    children: {\n      control: \"text\",\n    },\n  },\n  args: {\n    className: \"h-32 w-80 rounded-md border p-4\",\n    children:\n      \"Jokester began sneaking into the castle in the middle of the night and leaving jokes all over the place: under the king's pillow, in his soup, even in the royal toilet. The king was furious, but he couldn't seem to stop Jokester. And then, one day, the people of the kingdom discovered that the jokes left by Jokester were so funny that they couldn't help but laugh. And once they started laughing, they couldn't stop. The king was so angry that he banished Jokester from the kingdom, but the people still laughed, and they laughed, and they laughed. And they all lived happily ever after.\",\n  },\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof ScrollArea>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the scroll area.\n */\nexport const Default: Story = {};\n\n/**\n * Use the `overflowEdgeThreshold` prop to control when edge styles appear.\n */\nexport const WithEdgeThreshold: Story = {\n  args: {\n    overflowEdgeThreshold: 12,\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/select-story/select-base.stories.tsx",
      "content": "import { expect, fn, userEvent, waitFor, within } from \"storybook/test\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  Select,\n  SelectContent,\n  SelectGroup,\n  SelectItem,\n  SelectLabel,\n  SelectSeparator,\n  SelectTrigger,\n  SelectValue,\n} from \"@/components/ui/select\";\n\n/**\n * Displays a list of options for the user to pick from—triggered by a button.\n */\nconst meta: Meta<typeof Select> = {\n  title: \"ui/base/Select\",\n  component: Select,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {\n    onValueChange: fn(),\n  },\n  render: (args) => (\n    <Select {...args}>\n      <SelectTrigger title=\"Select\" className=\"w-96\">\n        <SelectValue placeholder=\"Select a fruit\" />\n      </SelectTrigger>\n      <SelectContent>\n        <SelectGroup>\n          <SelectLabel>Fruits</SelectLabel>\n          <SelectItem value=\"apple\">Apple</SelectItem>\n          <SelectItem value=\"banana\">Banana</SelectItem>\n          <SelectItem value=\"blueberry\">Blueberry</SelectItem>\n          <SelectItem value=\"grapes\">Grapes</SelectItem>\n          <SelectItem value=\"pineapple\">Pineapple</SelectItem>\n        </SelectGroup>\n        <SelectSeparator />\n        <SelectGroup>\n          <SelectLabel>Vegetables</SelectLabel>\n          <SelectItem value=\"aubergine\">Aubergine</SelectItem>\n          <SelectItem value=\"broccoli\">Broccoli</SelectItem>\n          <SelectItem value=\"carrot\" disabled>\n            Carrot\n          </SelectItem>\n          <SelectItem value=\"courgette\">Courgette</SelectItem>\n          <SelectItem value=\"leek\">Leek</SelectItem>\n        </SelectGroup>\n        <SelectSeparator />\n        <SelectGroup>\n          <SelectLabel>Meat</SelectLabel>\n          <SelectItem value=\"beef\">Beef</SelectItem>\n          <SelectItem value=\"chicken\">Chicken</SelectItem>\n          <SelectItem value=\"lamb\">Lamb</SelectItem>\n          <SelectItem value=\"pork\">Pork</SelectItem>\n        </SelectGroup>\n      </SelectContent>\n    </Select>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Select>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the select.\n */\nexport const Default: Story = {};\n\nexport const ShouldSelectOption: Story = {\n  name: \"when an option is selected, should be checked\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n    const select = await canvasBody.findByRole(\"combobox\");\n\n    await step(\"open and select item\", async () => {\n      await userEvent.click(select);\n      await userEvent.click(\n        await canvasBody.findByRole(\"option\", { name: /banana/i }),\n      );\n      await waitFor(() => {\n        expect(select).toHaveTextContent(/banana/i);\n      });\n    });\n\n    await step(\"verify the selected option\", async () => {\n      await userEvent.click(select);\n      const options = await canvasBody.findAllByRole(\"option\");\n      const selectedOption = options.find(\n        (option) =>\n          option.getAttribute(\"aria-selected\") === \"true\" &&\n          /banana/i.test(option.textContent ?? \"\"),\n      );\n      expect(selectedOption).toBeDefined();\n      await userEvent.click(\n        await canvasBody.findByRole(\"option\", { name: /banana/i }),\n      );\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/separator-story/separator-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport { Separator } from \"@/components/ui/separator\";\n\n/**\n * Visually or semantically separates content.\n */\nconst meta = {\n  title: \"ui/base/Separator\",\n  component: Separator,\n  tags: [\"autodocs\"],\n  argTypes: {},\n} satisfies Meta<typeof Separator>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default horizontal separator between vertical items.\n */\nexport const Default: Story = {\n  render: () => (\n    <div className=\"flex flex-col items-center justify-center gap-2\">\n      <div>Top</div>\n      <Separator orientation=\"horizontal\" />\n      <div>Bottom</div>\n    </div>\n  ),\n};\n\n/**\n * Use `orientation=\"vertical\"` for a vertical separator between horizontal items.\n */\nexport const Vertical: Story = {\n  render: () => (\n    <div className=\"flex h-12 items-center justify-center gap-2\">\n      <div>Left</div>\n      <Separator orientation=\"vertical\" />\n      <div>Right</div>\n    </div>\n  ),\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/sheet-story/sheet-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  Sheet,\n  SheetClose,\n  SheetContent,\n  SheetDescription,\n  SheetFooter,\n  SheetHeader,\n  SheetTitle,\n  SheetTrigger,\n} from \"@/components/ui/sheet\";\nimport { expect, userEvent, waitFor, within } from \"storybook/test\";\n\n/**\n * Extends the Dialog component to display content that complements the main\n * content of the screen.\n */\nconst meta: Meta<typeof SheetContent> = {\n  title: \"ui/base/Sheet\",\n  component: Sheet,\n  tags: [\"autodocs\"],\n  argTypes: {\n    side: {\n      options: [\"top\", \"bottom\", \"left\", \"right\"],\n      control: {\n        type: \"radio\",\n      },\n    },\n  },\n  args: {\n    side: \"right\",\n  },\n  render: (args) => (\n    <Sheet>\n      <SheetTrigger>Open</SheetTrigger>\n      <SheetContent {...args}>\n        <SheetHeader>\n          <SheetTitle>Are you absolutely sure?</SheetTitle>\n          <SheetDescription>\n            This action cannot be undone. This will permanently delete your\n            account and remove your data from our servers.\n          </SheetDescription>\n        </SheetHeader>\n        <SheetFooter>\n          <SheetClose className=\"hover:underline\">Cancel</SheetClose>\n          <SheetClose className=\"bg-primary text-primary-foreground rounded px-4 py-2\">\n            Submit\n          </SheetClose>\n        </SheetFooter>\n      </SheetContent>\n    </Sheet>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof SheetContent>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the sheet.\n */\nexport const Default: Story = {};\n\nexport const ShouldOpenCloseWithSubmit: Story = {\n  name: \"when clicking Submit button, should close the sheet\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n\n    await step(\"open the sheet\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /open/i }),\n      );\n      const sheet = await canvasBody.findByRole(\"dialog\");\n      await waitFor(() => {\n        expect(sheet).toHaveAttribute(\"data-open\");\n      });\n    });\n\n    await step(\"close the sheet\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /submit/i }),\n      );\n      await waitFor(() => {\n        expect(canvasBody.queryByRole(\"dialog\")).not.toBeInTheDocument();\n      });\n    });\n  },\n};\n\nexport const ShouldOpenCloseWithCancel: Story = {\n  name: \"when clicking Cancel button, should close the sheet\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n\n    await step(\"open the sheet\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /open/i }),\n      );\n      const sheet = await canvasBody.findByRole(\"dialog\");\n      await waitFor(() => {\n        expect(sheet).toHaveAttribute(\"data-open\");\n      });\n    });\n\n    await step(\"close the sheet\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /cancel/i }),\n      );\n      await waitFor(() => {\n        expect(canvasBody.queryByRole(\"dialog\")).not.toBeInTheDocument();\n      });\n    });\n  },\n};\n\nexport const ShouldOpenCloseWithClose: Story = {\n  name: \"when clicking Close icon, should close the sheet\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n\n    await step(\"open the sheet\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /open/i }),\n      );\n      const sheet = await canvasBody.findByRole(\"dialog\");\n      await waitFor(() => {\n        expect(sheet).toHaveAttribute(\"data-open\");\n      });\n    });\n\n    await step(\"close the sheet\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /close/i }),\n      );\n      await waitFor(() => {\n        expect(canvasBody.queryByRole(\"dialog\")).not.toBeInTheDocument();\n      });\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/sidebar-story/sidebar-base.stories.tsx",
      "content": "import { userEvent } from \"storybook/test\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport {\n  Sidebar,\n  SidebarContent,\n  SidebarFooter,\n  SidebarGroup,\n  SidebarGroupContent,\n  SidebarGroupLabel,\n  SidebarHeader,\n  SidebarMenu,\n  SidebarMenuButton,\n  SidebarMenuItem,\n  SidebarProvider,\n  SidebarTrigger,\n} from \"@/components/ui/sidebar\";\nimport {\n  Calendar,\n  ChevronUp,\n  Home,\n  Inbox,\n  Search,\n  Settings,\n  User2,\n} from \"lucide-react\";\n\n/**\n * A composable, themeable and customizable sidebar component.\n */\nconst meta = {\n  title: \"ui/base/Sidebar\",\n  component: Sidebar,\n  tags: [\"autodocs\"],\n  argTypes: {\n    side: {\n      options: [\"left\", \"right\"],\n      control: { type: \"radio\" },\n    },\n    variant: {\n      options: [\"sidebar\", \"floating\", \"inset\"],\n      control: { type: \"radio\" },\n    },\n    collapsible: {\n      options: [\"offcanvas\", \"icon\", \"none\"],\n      control: { type: \"radio\" },\n    },\n  },\n  args: {\n    side: \"left\",\n    variant: \"sidebar\",\n    collapsible: \"icon\",\n  },\n  parameters: {\n    layout: \"fullscreen\",\n  },\n  decorators: [\n    (Story) => (\n      <SidebarProvider>\n        <Story />\n        <section className=\"m-4\">\n          <SidebarTrigger />\n          <div className=\"size-full\" />\n        </section>\n      </SidebarProvider>\n    ),\n  ],\n} satisfies Meta<typeof Sidebar>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof Sidebar>;\n\n// Menu items.\nconst items = [\n  {\n    title: \"Home\",\n    url: \"#\",\n    icon: Home,\n  },\n  {\n    title: \"Inbox\",\n    url: \"#\",\n    icon: Inbox,\n  },\n  {\n    title: \"Calendar\",\n    url: \"#\",\n    icon: Calendar,\n  },\n  {\n    title: \"Search\",\n    url: \"#\",\n    icon: Search,\n  },\n  {\n    title: \"Settings\",\n    url: \"#\",\n    icon: Settings,\n  },\n];\n\n/**\n * A simple sidebar with a group of menu items.\n */\nexport const Simple: Story = {\n  render: (args) => (\n    <Sidebar {...args}>\n      <SidebarHeader />\n      <SidebarContent>\n        <SidebarGroup>\n          <SidebarGroupLabel>Application</SidebarGroupLabel>\n          <SidebarGroupContent>\n            <SidebarMenu>\n              {items.map((item) => (\n                <SidebarMenuItem key={item.title}>\n                  <SidebarMenuButton render={<a href={item.url} />}>\n                    <item.icon />\n                    <span>{item.title}</span>\n                  </SidebarMenuButton>\n                </SidebarMenuItem>\n              ))}\n            </SidebarMenu>\n          </SidebarGroupContent>\n        </SidebarGroup>\n      </SidebarContent>\n      <SidebarFooter />\n    </Sidebar>\n  ),\n};\n\n/**\n * A simple sidebar with a footer menu item.\n */\nexport const Footer: Story = {\n  render: (args) => (\n    <Sidebar {...args}>\n      <SidebarHeader />\n      <SidebarContent />\n      <SidebarFooter>\n        <SidebarMenu>\n          <SidebarMenuItem>\n            <DropdownMenu>\n              <DropdownMenuTrigger render={<SidebarMenuButton />}>\n                <User2 /> Username\n                <ChevronUp className=\"ml-auto\" />\n              </DropdownMenuTrigger>\n              <DropdownMenuContent side=\"top\" className=\"w-(--anchor-width)\">\n                <DropdownMenuItem>\n                  <span>Account</span>\n                </DropdownMenuItem>\n                <DropdownMenuItem>\n                  <span>Billing</span>\n                </DropdownMenuItem>\n                <DropdownMenuItem>\n                  <span>Sign out</span>\n                </DropdownMenuItem>\n              </DropdownMenuContent>\n            </DropdownMenu>\n          </SidebarMenuItem>\n        </SidebarMenu>\n      </SidebarFooter>\n    </Sidebar>\n  ),\n};\n\nexport const ShouldCloseOpen: Story = {\n  ...Simple,\n  name: \"when clicking the trigger, should close and open the sidebar\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvas, step }) => {\n    const sidebarBtn = await canvas.findByRole(\"button\", {\n      name: /toggle/i,\n    });\n    await step(\"close the sidebar\", async () => {\n      await userEvent.click(sidebarBtn);\n    });\n\n    await step(\"reopen the sidebar\", async () => {\n      await userEvent.click(sidebarBtn);\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/skeleton-story/skeleton-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport { Skeleton } from \"@/components/ui/skeleton\";\n\n/**\n * Use to show a placeholder while content is loading.\n */\nconst meta = {\n  title: \"ui/base/Skeleton\",\n  component: Skeleton,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Skeleton>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof Skeleton>;\n\n/**\n * The default form of the skeleton.\n */\nexport const Default: Story = {\n  render: (args) => (\n    <div className=\"flex items-center space-x-4\">\n      <Skeleton {...args} className=\"h-12 w-12 rounded-full\" />\n      <div className=\"space-y-2\">\n        <Skeleton {...args} className=\"h-4 w-[250px]\" />\n        <Skeleton {...args} className=\"h-4 w-[200px]\" />\n      </div>\n    </div>\n  ),\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/slider-story/slider-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport { Slider } from \"@/components/ui/slider\";\n\n/**\n * An input where the user selects a value from within a given range.\n */\nconst meta = {\n  title: \"ui/base/Slider\",\n  component: Slider,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {\n    defaultValue: [33],\n    max: 100,\n    step: 1,\n  },\n} satisfies Meta<typeof Slider>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the slider.\n */\nexport const Default: Story = {};\n\n/**\n * Use the `orientation` prop to render a vertical slider.\n */\nexport const Vertical: Story = {\n  args: {\n    orientation: \"vertical\",\n    className: \"h-40\",\n  },\n};\n\n/**\n * Use the `disabled` prop to disable the slider.\n */\nexport const Disabled: Story = {\n  args: {\n    disabled: true,\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/sonner-story/sonner-base.stories.tsx",
      "content": "import { action } from \"storybook/actions\";\nimport { expect, userEvent, waitFor, within } from \"storybook/test\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport { toast } from \"sonner\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Toaster } from \"@/components/ui/sonner\";\n\n/**\n * An opinionated toast component for React.\n */\nconst meta: Meta<typeof Toaster> = {\n  title: \"ui/base/Sonner\",\n  component: Toaster,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {\n    position: \"bottom-right\",\n  },\n  parameters: {\n    layout: \"fullscreen\",\n  },\n  render: (args) => (\n    <div className=\"flex min-h-96 items-center justify-center space-x-2\">\n      <Button\n        onClick={() =>\n          toast(\"Event has been created\", {\n            description: new Date().toLocaleString(),\n            action: {\n              label: \"Undo\",\n              onClick: action(\"Undo clicked\"),\n            },\n          })\n        }\n      >\n        Show Toast\n      </Button>\n      <Toaster {...args} />\n    </div>\n  ),\n} satisfies Meta<typeof Toaster>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the toaster.\n */\nexport const Default: Story = {};\n\nexport const ShouldShowToast: Story = {\n  name: \"when clicking Show Toast button, should show a toast\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n    const triggerBtn = await canvasBody.findByRole(\"button\", {\n      name: /show/i,\n    });\n\n    await step(\"create a toast\", async () => {\n      await userEvent.click(triggerBtn);\n      await waitFor(() =>\n        expect(canvasBody.queryByRole(\"listitem\")).toBeInTheDocument(),\n      );\n    });\n\n    await step(\"create more toasts\", async () => {\n      await userEvent.click(triggerBtn);\n      await userEvent.click(triggerBtn);\n      await waitFor(() =>\n        expect(canvasBody.getAllByRole(\"listitem\")).toHaveLength(3),\n      );\n    });\n  },\n};\n\nexport const ShouldCloseToast: Story = {\n  name: \"when clicking the close button, should close the toast\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n    const triggerBtn = await canvasBody.findByRole(\"button\", {\n      name: /show/i,\n    });\n\n    await step(\"create a toast\", async () => {\n      await userEvent.click(triggerBtn);\n    });\n\n    await step(\"close the toast\", async () => {\n      await userEvent.click(\n        await canvasBody.findByRole(\"button\", { name: /undo/i }),\n      );\n      await waitFor(() =>\n        expect(canvasBody.queryByRole(\"listitem\")).not.toBeInTheDocument(),\n      );\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/spinner-story/spinner-base.stories.tsx",
      "content": "import type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport { ArrowUpIcon } from \"lucide-react\";\n\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n  Empty,\n  EmptyContent,\n  EmptyDescription,\n  EmptyHeader,\n  EmptyMedia,\n  EmptyTitle,\n} from \"@/components/ui/empty\";\nimport {\n  InputGroup,\n  InputGroupAddon,\n  InputGroupButton,\n  InputGroupInput,\n  InputGroupTextarea,\n} from \"@/components/ui/input-group\";\nimport {\n  Item,\n  ItemContent,\n  ItemMedia,\n  ItemTitle,\n} from \"@/components/ui/item\";\nimport { Spinner } from \"@/components/ui/spinner\";\n\n/**\n * An indicator that can be used to show a loading state.\n */\nconst meta: Meta<typeof Spinner> = {\n  title: \"ui/base/Spinner\",\n  component: Spinner,\n  tags: [\"autodocs\"],\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Spinner>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default spinner with payment processing example.\n */\nexport const WithItem: Story = {\n  render: (args) => (\n    <div className=\"flex w-full max-w-xs flex-col gap-4 [--radius:1rem]\">\n      <Item variant=\"muted\">\n        <ItemMedia>\n          <Spinner {...args} />\n        </ItemMedia>\n        <ItemContent>\n          <ItemTitle className=\"line-clamp-1\">Processing payment...</ItemTitle>\n        </ItemContent>\n        <ItemContent className=\"flex-none justify-end\">\n          <span className=\"text-sm tabular-nums\">$100.00</span>\n        </ItemContent>\n      </Item>\n    </div>\n  ),\n};\n\n/**\n * Add a spinner to a button to indicate a loading state.\n */\nexport const WithButton: Story = {\n  render: (args) => (\n    <Button disabled size=\"sm\">\n      <Spinner {...args} />\n      Loading...\n    </Button>\n  ),\n};\n\n/**\n * You can also use a spinner inside a badge.\n */\nexport const WithBadge: Story = {\n  render: (args) => (\n    <Badge>\n      <Spinner {...args} />\n      Syncing\n    </Badge>\n  ),\n};\n\n/**\n * Input Group can have spinners inside InputGroupAddon.\n */\nexport const WithInputGroup: Story = {\n  render: (args) => (\n    <div className=\"flex w-full max-w-md flex-col gap-4\">\n      <InputGroup>\n        <InputGroupInput placeholder=\"Send a message...\" disabled />\n        <InputGroupAddon align=\"inline-end\">\n          <Spinner {...args} />\n        </InputGroupAddon>\n      </InputGroup>\n      <InputGroup>\n        <InputGroupTextarea placeholder=\"Send a message...\" disabled />\n        <InputGroupAddon align=\"block-end\">\n          <Spinner /> Validating...\n          <InputGroupButton className=\"ml-auto\" variant=\"default\">\n            <ArrowUpIcon />\n            <span className=\"sr-only\">Send</span>\n          </InputGroupButton>\n        </InputGroupAddon>\n      </InputGroup>\n    </div>\n  ),\n};\n\n/**\n * Spinner used in Empty component for loading states.\n */\nexport const WithEmpty: Story = {\n  render: (args) => (\n    <Empty className=\"w-full\">\n      <EmptyHeader>\n        <EmptyMedia variant=\"icon\">\n          <Spinner {...args} />\n        </EmptyMedia>\n        <EmptyTitle>Processing your request</EmptyTitle>\n        <EmptyDescription>\n          Please wait while we process your request. Do not refresh the page.\n        </EmptyDescription>\n      </EmptyHeader>\n      <EmptyContent>\n        <Button variant=\"outline\" size=\"sm\">\n          Cancel\n        </Button>\n      </EmptyContent>\n    </Empty>\n  ),\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/switch-story/switch-base.stories.tsx",
      "content": "import { expect, userEvent } from \"storybook/test\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport { Label } from \"@/components/ui/label\";\nimport { Switch } from \"@/components/ui/switch\";\n\n/**\n * A control that allows the user to toggle between checked and not checked.\n */\nconst meta = {\n  title: \"ui/base/Switch\",\n  component: Switch,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  parameters: {\n    layout: \"centered\",\n  },\n  render: (args) => (\n    <div className=\"flex items-center space-x-2\">\n      <Switch {...args} />\n      <Label htmlFor={args.id}>Airplane Mode</Label>\n    </div>\n  ),\n} satisfies Meta<typeof Switch>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the switch.\n */\nexport const Default: Story = {\n  args: {\n    id: \"default-switch\",\n  },\n};\n\n/**\n * Use the `disabled` prop to disable the switch.\n */\nexport const Disabled: Story = {\n  args: {\n    id: \"disabled-switch\",\n    disabled: true,\n  },\n};\n\nexport const ShouldToggle: Story = {\n  name: \"when clicking the switch, should toggle it on and off\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvas, step }) => {\n    const switchBtn = await canvas.findByRole(\"switch\");\n\n    await step(\"toggle the switch on\", async () => {\n      await userEvent.click(switchBtn);\n      await expect(switchBtn).toBeChecked();\n    });\n\n    await step(\"toggle the switch off\", async () => {\n      await userEvent.click(switchBtn);\n      await expect(switchBtn).not.toBeChecked();\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/table-story/table-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  Table,\n  TableBody,\n  TableCaption,\n  TableCell,\n  TableHead,\n  TableHeader,\n  TableRow,\n} from \"@/components/ui/table\";\n\nconst invoices = [\n  {\n    invoice: \"INV001\",\n    paymentStatus: \"Paid\",\n    totalAmount: \"$250.00\",\n    paymentMethod: \"Credit Card\",\n  },\n  {\n    invoice: \"INV002\",\n    paymentStatus: \"Pending\",\n    totalAmount: \"$150.00\",\n    paymentMethod: \"PayPal\",\n  },\n  {\n    invoice: \"INV003\",\n    paymentStatus: \"Unpaid\",\n    totalAmount: \"$350.00\",\n    paymentMethod: \"Bank Transfer\",\n  },\n  {\n    invoice: \"INV004\",\n    paymentStatus: \"Paid\",\n    totalAmount: \"$450.00\",\n    paymentMethod: \"Credit Card\",\n  },\n];\n\n/**\n * Powerful table and datagrids built using TanStack Table.\n */\nconst meta = {\n  title: \"ui/base/Table\",\n  component: Table,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  render: (args) => (\n    <Table {...args}>\n      <TableCaption>A list of your recent invoices.</TableCaption>\n      <TableHeader>\n        <TableRow>\n          <TableHead className=\"w-[100px]\">Invoice</TableHead>\n          <TableHead>Status</TableHead>\n          <TableHead>Method</TableHead>\n          <TableHead className=\"text-right\">Amount</TableHead>\n        </TableRow>\n      </TableHeader>\n      <TableBody>\n        {invoices.map((invoice) => (\n          <TableRow key={invoice.invoice}>\n            <TableCell className=\"font-medium\">{invoice.invoice}</TableCell>\n            <TableCell>{invoice.paymentStatus}</TableCell>\n            <TableCell>{invoice.paymentMethod}</TableCell>\n            <TableCell className=\"text-right\">{invoice.totalAmount}</TableCell>\n          </TableRow>\n        ))}\n      </TableBody>\n    </Table>\n  ),\n} satisfies Meta<typeof Table>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the table.\n */\nexport const Default: Story = {};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/tabs-story/tabs-base.stories.tsx",
      "content": "import { expect, userEvent, waitFor } from \"storybook/test\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport {\n  Tabs,\n  TabsContent,\n  TabsList,\n  TabsTrigger,\n} from \"@/components/ui/tabs\";\n\n/**\n * A set of layered sections of content—known as tab panels—that are displayed\n * one at a time.\n */\nconst meta = {\n  title: \"ui/base/Tabs\",\n  component: Tabs,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {\n    defaultValue: \"account\",\n    className: \"w-96\",\n  },\n  render: (args) => (\n    <Tabs {...args}>\n      <TabsList className=\"grid grid-cols-2\">\n        <TabsTrigger value=\"account\">Account</TabsTrigger>\n        <TabsTrigger value=\"password\">Password</TabsTrigger>\n      </TabsList>\n      <TabsContent value=\"account\">\n        Make changes to your account here.\n      </TabsContent>\n      <TabsContent value=\"password\">Change your password here.</TabsContent>\n    </Tabs>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Tabs>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the tabs.\n */\nexport const Default: Story = {};\n\nexport const ShouldChangeTabs: Story = {\n  name: \"when clicking a tab, should change the content\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvas, step }) => {\n    const tabs = await canvas.findAllByRole(\"tab\");\n\n    for (let i = 0; i < tabs.length; i++) {\n      await step(`click the '${tabs[i].innerText}' tab`, async () => {\n        await userEvent.click(tabs[i]);\n        await waitFor(() =>\n          expect(tabs[i]).toHaveAttribute(\"aria-selected\", \"true\"),\n        );\n        await expect(\n          await canvas.queryByRole(\"tabpanel\", { name: tabs[i].innerText }),\n        ).toBeVisible();\n      });\n\n      await step(\"check other tabs are not selected\", async () => {\n        for (let j = 0; j < tabs.length; j++) {\n          if (j !== i) {\n            expect(tabs[j]).toHaveAttribute(\"aria-selected\", \"false\");\n            expect(\n              await canvas.queryByRole(\"tabpanel\", { name: tabs[j].innerText }),\n            ).toBeNull();\n          }\n        }\n      });\n    }\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/textarea-story/textarea-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Label } from \"@/components/ui/label\";\nimport { Textarea } from \"@/components/ui/textarea\";\n\n/**\n * Displays a form textarea or a component that looks like a textarea.\n */\nconst meta = {\n  title: \"ui/base/Textarea\",\n  component: Textarea,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  args: {\n    placeholder: \"Type your message here.\",\n    disabled: false,\n  },\n} satisfies Meta<typeof Textarea>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the textarea.\n */\nexport const Default: Story = {};\n\n/**\n * Use the `disabled` prop to disable the textarea.\n */\nexport const Disabled: Story = {\n  args: {\n    disabled: true,\n  },\n};\n\n/**\n * Use the `Label` component to includes a clear, descriptive label above or\n * alongside the text area to guide users.\n */\nexport const WithLabel: Story = {\n  render: (args) => (\n    <div className=\"grid w-full gap-1.5\">\n      <Label htmlFor=\"message\">Your message</Label>\n      <Textarea {...args} id=\"message\" />\n    </div>\n  ),\n};\n\n/**\n * Use a text element below the text area to provide additional instructions\n * or information to users.\n */\nexport const WithText: Story = {\n  render: (args) => (\n    <div className=\"grid w-full gap-1.5\">\n      <Label htmlFor=\"message-2\">Your Message</Label>\n      <Textarea {...args} id=\"message-2\" />\n      <p className=\"text-sm text-slate-500\">\n        Your message will be copied to the support team.\n      </p>\n    </div>\n  ),\n};\n\n/**\n * Use the `Button` component to indicate that the text area can be submitted\n * or used to trigger an action.\n */\nexport const WithButton: Story = {\n  render: (args) => (\n    <div className=\"grid w-full gap-2\">\n      <Textarea {...args} />\n      <Button type=\"submit\">Send Message</Button>\n    </div>\n  ),\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/toggle-story/toggle-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport { Bold, Italic } from \"lucide-react\";\n\nimport { Toggle } from \"@/components/ui/toggle\";\n\n/**\n * A two-state button that can be either on or off.\n */\nconst meta: Meta<typeof Toggle> = {\n  title: \"ui/base/Toggle\",\n  component: Toggle,\n  tags: [\"autodocs\"],\n  argTypes: {\n    children: {\n      control: { disable: true },\n    },\n  },\n  args: {\n    children: <Bold className=\"h-4 w-4\" />,\n    \"aria-label\": \"Toggle bold\",\n  },\n  parameters: {\n    layout: \"centered\",\n  },\n};\nexport default meta;\n\ntype Story = StoryObj<typeof Toggle>;\n\n/**\n * The default form of the toggle.\n */\nexport const Default: Story = {};\n\n/**\n * Use the `outline` variant for a distinct outline, emphasizing the boundary\n * of the selection circle for clearer visibility\n */\nexport const Outline: Story = {\n  args: {\n    variant: \"outline\",\n    children: <Italic className=\"h-4 w-4\" />,\n    \"aria-label\": \"Toggle italic\",\n  },\n};\n\n/**\n * Use the text element to add a label to the toggle.\n */\nexport const WithText: Story = {\n  render: (args) => (\n    <Toggle {...args}>\n      <Italic className=\"mr-2 h-4 w-4\" />\n      Italic\n    </Toggle>\n  ),\n  args: { ...Outline.args },\n};\n\n/**\n * Use the `sm` size for a smaller toggle, suitable for interfaces needing\n * compact elements without sacrificing usability.\n */\nexport const Small: Story = {\n  args: {\n    size: \"sm\",\n  },\n};\n\n/**\n * Use the `lg` size for a larger toggle, offering better visibility and\n * easier interaction for users.\n */\nexport const Large: Story = {\n  args: {\n    size: \"lg\",\n  },\n};\n\n/**\n * Add the `disabled` prop to prevent interactions with the toggle.\n */\nexport const Disabled: Story = {\n  args: {\n    disabled: true,\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/toggle-group-story/toggle-group-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport { Bold, Italic, Underline } from \"lucide-react\";\n\nimport {\n  ToggleGroup,\n  ToggleGroupItem,\n} from \"@/components/ui/toggle-group\";\n\n/**\n * A set of two-state buttons that can be toggled on or off.\n */\nconst meta = {\n  title: \"ui/base/ToggleGroup\",\n  component: ToggleGroup,\n  tags: [\"autodocs\"],\n  argTypes: {\n    multiple: {\n      options: [true, false],\n      control: { type: \"radio\" },\n    },\n  },\n  args: {\n    variant: \"default\",\n    size: \"default\",\n    multiple: true,\n    disabled: false,\n  },\n  render: (args) => (\n    <ToggleGroup {...args}>\n      <ToggleGroupItem value=\"bold\" aria-label=\"Toggle bold\">\n        <Bold className=\"h-4 w-4\" />\n      </ToggleGroupItem>\n      <ToggleGroupItem value=\"italic\" aria-label=\"Toggle italic\">\n        <Italic className=\"h-4 w-4\" />\n      </ToggleGroupItem>\n      <ToggleGroupItem value=\"underline\" aria-label=\"Toggle underline\">\n        <Underline className=\"h-4 w-4\" />\n      </ToggleGroupItem>\n    </ToggleGroup>\n  ),\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof ToggleGroup>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the toggle group.\n */\nexport const Default: Story = {};\n\n/**\n * Use the `outline` variant to emphasizing the individuality of each button\n * while keeping them visually cohesive.\n */\nexport const Outline: Story = {\n  args: {\n    variant: \"outline\",\n  },\n};\n\n/**\n * Use the `single` type to create exclusive selection within the button\n * group, allowing only one button to be active at a time.\n */\nexport const Single: Story = {\n  args: {\n    multiple: false,\n  },\n};\n\n/**\n * Use the `sm` size for a compact version of the button group, featuring\n * smaller buttons for spaces with limited real estate.\n */\nexport const Small: Story = {\n  args: {\n    size: \"sm\",\n  },\n};\n\n/**\n * Use the `lg` size for a more prominent version of the button group, featuring\n * larger buttons for emphasis.\n */\nexport const Large: Story = {\n  args: {\n    size: \"lg\",\n  },\n};\n\n/**\n * Add the `disabled` prop to a button to prevent interactions.\n */\nexport const Disabled: Story = {\n  args: {\n    disabled: true,\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/ui/tooltip-story/tooltip-base.stories.tsx",
      "content": "// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport { Plus } from \"lucide-react\";\n\nimport {\n  Tooltip,\n  TooltipContent,\n  TooltipProvider,\n  TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { expect, userEvent, waitFor, within } from \"storybook/test\";\n\n/**\n * A popup that displays information related to an element when the element\n * receives keyboard focus or the mouse hovers over it.\n */\nconst meta: Meta<typeof TooltipContent> = {\n  title: \"ui/base/Tooltip\",\n  component: TooltipContent,\n  tags: [\"autodocs\"],\n  argTypes: {\n    side: {\n      options: [\"top\", \"bottom\", \"left\", \"right\"],\n      control: {\n        type: \"radio\",\n      },\n    },\n    children: {\n      control: \"text\",\n    },\n  },\n  args: {\n    side: \"top\",\n    children: \"Add to library\",\n  },\n  parameters: {\n    layout: \"centered\",\n  },\n  render: (args) => (\n    <TooltipProvider>\n      <Tooltip>\n        <TooltipTrigger>\n          <Plus className=\"h-4 w-4\" />\n          <span className=\"sr-only\">Add</span>\n        </TooltipTrigger>\n        <TooltipContent {...args} />\n      </Tooltip>\n    </TooltipProvider>\n  ),\n} satisfies Meta<typeof TooltipContent>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * The default form of the tooltip.\n */\nexport const Default: Story = {};\n\n/**\n * Use the `bottom` side to display the tooltip below the element.\n */\nexport const Bottom: Story = {\n  args: {\n    side: \"bottom\",\n  },\n};\n\n/**\n * Use the `left` side to display the tooltip to the left of the element.\n */\nexport const Left: Story = {\n  args: {\n    side: \"left\",\n  },\n};\n\n/**\n * Use the `right` side to display the tooltip to the right of the element.\n */\nexport const Right: Story = {\n  args: {\n    side: \"right\",\n  },\n};\n\nexport const ShouldShowOnHover: Story = {\n  name: \"when hovering over trigger, should show hover tooltip content\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvasBody = within(canvasElement.ownerDocument.body);\n    const triggerBtn = await canvasBody.findByRole(\"button\", { name: /add/i });\n\n    await step(\"hover over trigger\", async () => {\n      await userEvent.hover(triggerBtn);\n      await waitFor(() =>\n        expect(\n          canvasElement.ownerDocument.body.querySelector(\n            \"[data-slot=tooltip-content]\",\n          ),\n        ).toBeVisible(),\n      );\n    });\n\n    await step(\"unhover trigger\", async () => {\n      await userEvent.unhover(triggerBtn);\n      await waitFor(() => {\n        const tooltipElement = canvasElement.ownerDocument.body.querySelector(\n          \"[data-slot=tooltip-content]\",\n        );\n        expect(tooltipElement).toBeNull();\n      });\n    });\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/tokens/color-story/color-base.stories.tsx",
      "content": "import {\n  Table,\n  TableBody,\n  TableCell,\n  TableHead,\n  TableHeader,\n  TableRow,\n} from \"@/components/ui/table\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\ntype Swatch = {\n  name: string;\n  colors: Record<string, string>;\n};\n\nconst SwatchList = ({ colors }: { colors: Record<string, string> }) => {\n  return (\n    <div className=\"flex overflow-clip rounded-md border shadow\">\n      {Object.entries(colors).map(([name, value], idx) => {\n        const styles = getComputedStyle(document.documentElement);\n        const color = styles.getPropertyValue(value);\n\n        return (\n          <div\n            key={idx}\n            className=\"bg-background flex w-full flex-col gap-1 pb-3\"\n          >\n            <div className=\"h-16 w-full\" style={{ backgroundColor: color }} />\n            <p className=\"text-center font-semibold\">{name}</p>\n            <p className=\"text-center text-xs opacity-70\">{value}</p>\n            <p className=\"text-center text-xs\">{color}</p>\n          </div>\n        );\n      })}\n    </div>\n  );\n};\n\n/**\n * Color tokens for the design system\n */\nconst meta: Meta<{\n  swatch: Swatch[];\n}> = {\n  title: \"design/base/Color\",\n  argTypes: {},\n  render: (args) => (\n    <Table>\n      <TableHeader>\n        <TableRow>\n          <TableHead>Name</TableHead>\n          <TableHead>\n            <span className=\"sr-only\">Swatch</span>\n          </TableHead>\n        </TableRow>\n      </TableHeader>\n      <TableBody>\n        {args.swatch.map(({ name, colors }) => (\n          <TableRow key={name}>\n            <TableCell>{name}</TableCell>\n            <TableCell>\n              <SwatchList colors={colors} />\n            </TableCell>\n          </TableRow>\n        ))}\n      </TableBody>\n    </Table>\n  ),\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * Functional color tokens are used to define the core colors of the design system.\n * These colors are used throughout the application for backgrounds, text, borders, etc.\n */\nexport const Functional: Story = {\n  args: {\n    swatch: [\n      {\n        name: \"Background\",\n        colors: {\n          default: \"--background\",\n          foreground: \"--foreground\",\n        },\n      },\n      {\n        name: \"Primary\",\n        colors: {\n          default: \"--primary\",\n          foreground: \"--primary-foreground\",\n        },\n      },\n      {\n        name: \"Secondary\",\n        colors: {\n          default: \"--secondary\",\n          foreground: \"--secondary-foreground\",\n        },\n      },\n      {\n        name: \"Accent\",\n        colors: {\n          default: \"--accent\",\n          foreground: \"--accent-foreground\",\n        },\n      },\n      {\n        name: \"Muted\",\n        colors: {\n          default: \"--muted\",\n          foreground: \"--muted-foreground\",\n        },\n      },\n\n      {\n        name: \"Destructive\",\n        colors: {\n          default: \"--destructive\",\n        },\n      },\n    ],\n  },\n};\n\n/**\n * Component color tokens are used to define the colors of specific components in the design system.\n * These colors are used to style components like buttons, inputs, and alerts.\n */\nexport const Component: Story = {\n  args: {\n    swatch: [\n      {\n        name: \"Border\",\n        colors: {\n          default: \"--border\",\n          ring: \"--ring\",\n        },\n      },\n      {\n        name: \"Card\",\n        colors: {\n          default: \"--card\",\n          foreground: \"--card-foreground\",\n        },\n      },\n      {\n        name: \"Input\",\n        colors: {\n          default: \"--input\",\n        },\n      },\n      {\n        name: \"Popover\",\n        colors: {\n          default: \"--popover\",\n          foreground: \"--popover-foreground\",\n        },\n      },\n      {\n        name: \"Chart\",\n        colors: {\n          \"1\": \"--chart-1\",\n          \"2\": \"--chart-2\",\n          \"3\": \"--chart-3\",\n          \"4\": \"--chart-4\",\n          \"5\": \"--chart-5\",\n        },\n      },\n      {\n        name: \"Sidebar\",\n        colors: {\n          background: \"--sidebar\",\n          foreground: \"--sidebar-foreground\",\n          primary: \"--sidebar-primary\",\n          \"primary-foreground\": \"--sidebar-primary-foreground\",\n          accent: \"--sidebar-accent\",\n          \"accent-foreground\": \"--sidebar-accent-foreground\",\n          border: \"--sidebar-border\",\n          ring: \"--sidebar-ring\",\n        },\n      },\n    ],\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/tokens/radius-story/radius-base.stories.tsx",
      "content": "import {\n  Table,\n  TableBody,\n  TableCell,\n  TableHead,\n  TableHeader,\n  TableRow,\n} from \"@/components/ui/table\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\ntype Radius = {\n  name: string;\n  value: string;\n};\n\nconst RadiusTile = ({ value }: Pick<Radius, \"value\">) => {\n  const style = window.getComputedStyle(document.body);\n  const radius = style.getPropertyValue(value);\n\n  return (\n    <div className=\"flex flex-col items-center gap-2\">\n      <div\n        className=\"bg-card size-20 border-2\"\n        style={{ borderRadius: radius }}\n      />\n      <p className=\"text-center text-xs opacity-70\">{value}</p>\n      <p className=\"text-center text-xs\">{radius}</p>\n    </div>\n  );\n};\n\n/**\n * Radius tokens for the design system\n */\nconst meta: Meta<{\n  radius: Radius[];\n}> = {\n  title: \"design/base/Radius\",\n  argTypes: {},\n  render: (args) => (\n    <Table>\n      <TableHeader>\n        <TableRow>\n          <TableHead>Name</TableHead>\n          <TableHead>\n            <span className=\"sr-only\">Preview</span>\n          </TableHead>\n        </TableRow>\n      </TableHeader>\n      <TableBody>\n        {args.radius.map(({ name, value }) => (\n          <TableRow key={name}>\n            <TableCell>{name}</TableCell>\n            <TableCell>\n              <RadiusTile value={value} />\n            </TableCell>\n          </TableRow>\n        ))}\n      </TableBody>\n    </Table>\n  ),\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * Border radius tokens used for UI elements like buttons, cards, and modals.\n */\nexport const Core: Story = {\n  args: {\n    radius: [\n      { name: \"xs\", value: \"--radius-xs\" },\n      { name: \"sm\", value: \"--radius-sm\" },\n      { name: \"md\", value: \"--radius-md\" },\n      { name: \"lg\", value: \"--radius-lg\" },\n    ],\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/tokens/shadow-story/shadow-base.stories.tsx",
      "content": "import {\n  Table,\n  TableBody,\n  TableCell,\n  TableHead,\n  TableHeader,\n  TableRow,\n} from \"@/components/ui/table\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\ntype Shadow = {\n  name: string;\n  value: string;\n};\n\nconst ShadowTile = ({ value }: Pick<Shadow, \"value\">) => {\n  const style = window.getComputedStyle(document.body);\n  const shadow = style.getPropertyValue(value);\n\n  return (\n    <div className=\"flex flex-col items-center gap-2\">\n      <div\n        className=\"bg-card size-20 rounded-md\"\n        style={{ boxShadow: shadow }}\n      />\n      <p className=\"text-center text-xs opacity-70\">{value}</p>\n      <p className=\"text-center text-xs\">{shadow}</p>\n    </div>\n  );\n};\n\n/**\n * Shadow tokens for the design system\n */\nconst meta: Meta<{\n  shadow: Shadow[];\n}> = {\n  title: \"design/base/Shadow\",\n  argTypes: {},\n  render: (args) => (\n    <Table>\n      <TableHeader>\n        <TableRow>\n          <TableHead>Name</TableHead>\n          <TableHead>\n            <span className=\"sr-only shadow-2xl\">Preview</span>\n          </TableHead>\n        </TableRow>\n      </TableHeader>\n      <TableBody>\n        {args.shadow.map(({ name, value }) => (\n          <TableRow key={name}>\n            <TableCell>{name}</TableCell>\n            <TableCell>\n              <ShadowTile value={value} />\n            </TableCell>\n          </TableRow>\n        ))}\n      </TableBody>\n    </Table>\n  ),\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * Box shadow tokens used for UI elements like cards, modals, and overlays.\n */\nexport const Core: Story = {\n  args: {\n    shadow: [\n      { name: \"xxs\", value: \"--shadow-2xs\" },\n      { name: \"xs\", value: \"--shadow-xs\" },\n      { name: \"sm\", value: \"--shadow-sm\" },\n      { name: \"md\", value: \"--shadow-md\" },\n      { name: \"lg\", value: \"--shadow-lg\" },\n      { name: \"xl\", value: \"--shadow-xl\" },\n      { name: \"2xl\", value: \"--shadow-2xl\" },\n    ],\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/tokens/spacing-story/spacing-base.stories.tsx",
      "content": "import {\n  Table,\n  TableBody,\n  TableCell,\n  TableHead,\n  TableHeader,\n  TableRow,\n} from \"@/components/ui/table\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\ntype Spacing = {\n  name: string;\n  value: number;\n};\n\nconst SpacingRow = ({ value, name }: Spacing) => {\n  const style = window.getComputedStyle(document.body);\n  const size = style.getPropertyValue(\"--spacing\");\n  const rem = parseFloat(size) * value;\n  const pixels = parseFloat(size) * 16 * value;\n  return (\n    <TableRow>\n      <TableCell>{name}</TableCell>\n      <TableCell>{rem}rem</TableCell>\n      <TableCell>{pixels}px</TableCell>\n      <TableCell className=\"w-full\">\n        <div className=\"bg-muted border\">\n          <div className=\"bg-primary h-4\" style={{ width: pixels }} />\n        </div>\n      </TableCell>\n    </TableRow>\n  );\n};\n\n/**\n * Spacing tokens for the design system\n */\nconst meta: Meta<{\n  scale: Spacing[];\n}> = {\n  title: \"design/base/Spacing\",\n  argTypes: {},\n  render: (args) => (\n    <Table>\n      <TableHeader>\n        <TableRow>\n          <TableHead>Name</TableHead>\n          <TableHead>Size</TableHead>\n          <TableHead>Pixels</TableHead>\n          <TableHead className=\"hidden sm:table-cell\">\n            <span className=\"sr-only\">Preview</span>\n          </TableHead>\n        </TableRow>\n      </TableHeader>\n      <TableBody>\n        {args.scale.map(({ name, value }, idx) => (\n          <SpacingRow key={idx} value={value} name={name} />\n        ))}\n      </TableBody>\n    </Table>\n  ),\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * Spacing values used for padding, margins, and layout.\n */\nexport const Core: Story = {\n  args: {\n    scale: [\n      { name: \"x-1\", value: 1 },\n      { name: \"x-4\", value: 4 },\n      { name: \"x-8\", value: 8 },\n      { name: \"x-12\", value: 12 },\n      { name: \"x-16\", value: 16 },\n      { name: \"x-20\", value: 20 },\n      { name: \"x-24\", value: 24 },\n      { name: \"x-28\", value: 28 },\n      { name: \"x-32\", value: 32 },\n      { name: \"x-36\", value: 36 },\n      { name: \"x-40\", value: 40 },\n      { name: \"x-44\", value: 44 },\n      { name: \"x-48\", value: 48 },\n      { name: \"x-52\", value: 52 },\n      { name: \"x-56\", value: 56 },\n      { name: \"x-60\", value: 60 },\n      { name: \"x-64\", value: 64 },\n      { name: \"x-68\", value: 68 },\n      { name: \"x-72\", value: 72 },\n      { name: \"x-76\", value: 76 },\n      { name: \"x-80\", value: 80 },\n    ],\n  },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "registry/tokens/typography-story/typography-base.stories.tsx",
      "content": "import {\n  Table,\n  TableBody,\n  TableCell,\n  TableHead,\n  TableHeader,\n  TableRow,\n} from \"@/components/ui/table\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\nimport type { CSSProperties, ReactNode } from \"react\";\n\ntype Typography = {\n  name: string;\n  value: string;\n};\n\nconst TypographyRow = ({\n  value,\n  name,\n  styleKey,\n  children,\n}: {\n  value: string;\n  name: string;\n  styleKey: keyof CSSProperties;\n  children?: ReactNode;\n}) => {\n  const style = window.getComputedStyle(document.body);\n  const styleValue = style.getPropertyValue(value);\n  return (\n    <TableRow>\n      <TableCell>{name}</TableCell>\n      <TableCell>\n        {styleValue.split(\",\").map((v, idx) => (\n          <p key={`prop-${idx}`}>{v}</p>\n        ))}\n      </TableCell>\n      <TableCell>\n        <div style={{ [styleKey]: styleValue }} className=\"line-clamp-1\">\n          {children}\n        </div>\n      </TableCell>\n    </TableRow>\n  );\n};\n\n/**\n * Typography tokens for the design system.\n */\nconst meta: Meta<{\n  children: string;\n  key: keyof CSSProperties;\n  property: Typography[];\n}> = {\n  title: \"design/base/Typography\",\n  argTypes: {},\n  args: {\n    children: \"Typeface\",\n  },\n  render: (args) => (\n    <Table>\n      <TableHeader>\n        <TableRow>\n          <TableHead>Name</TableHead>\n          <TableHead>Property</TableHead>\n          <TableHead>\n            <span className=\"sr-only\">Preview</span>\n          </TableHead>\n        </TableRow>\n      </TableHeader>\n      <TableBody>\n        {args.property.map(({ name, value }) => (\n          <TypographyRow\n            key={name}\n            name={name}\n            value={value}\n            styleKey={args.key}\n          >\n            {args.children}\n          </TypographyRow>\n        ))}\n      </TableBody>\n    </Table>\n  ),\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * Font family tokens for the design system.\n */\nexport const FontFamily: Story = {\n  args: {\n    key: \"fontFamily\",\n    property: [\n      { name: \"sans\", value: \"--font-sans\" },\n      { name: \"serif\", value: \"--font-serif\" },\n      { name: \"mono\", value: \"--font-mono\" },\n    ],\n  },\n};\n\n/**\n * Font size tokens for the design system.\n */\nexport const FontSize: Story = {\n  args: {\n    key: \"fontSize\",\n    property: [\n      { name: \"xs\", value: \"--text-xs\" },\n      { name: \"sm\", value: \"--text-sm\" },\n      { name: \"base\", value: \"--text-base\" },\n      { name: \"lg\", value: \"--text-lg\" },\n      { name: \"xl\", value: \"--text-xl\" },\n      { name: \"2xl\", value: \"--text-2xl\" },\n      { name: \"3xl\", value: \"--text-3xl\" },\n      { name: \"4xl\", value: \"--text-4xl\" },\n      { name: \"5xl\", value: \"--text-5xl\" },\n      { name: \"6xl\", value: \"--text-6xl\" },\n    ],\n  },\n};\n\n/**\n * Font weight tokens for the design system.\n */\nexport const FontWeight: Story = {\n  args: {\n    key: \"fontWeight\",\n    property: [\n      { name: \"thin\", value: \"--font-weight-thin\" },\n      { name: \"extralight\", value: \"--font-weight-extralight\" },\n      { name: \"light\", value: \"--font-weight-light\" },\n      { name: \"normal\", value: \"--font-weight-normal\" },\n      { name: \"medium\", value: \"--font-weight-medium\" },\n      { name: \"semibold\", value: \"--font-weight-semibold\" },\n      { name: \"bold\", value: \"--font-weight-bold\" },\n      { name: \"extrabold\", value: \"--font-weight-extrabold\" },\n      { name: \"black\", value: \"--font-weight-black\" },\n    ],\n  },\n};\n\n/**\n * Letter Spacing tokens for the design system.\n */\nexport const LetterSpacing: Story = {\n  args: {\n    key: \"letterSpacing\",\n    property: [\n      { name: \"tighter\", value: \"--tracking-tighter\" },\n      { name: \"tight\", value: \"--tracking-tight\" },\n      { name: \"normal\", value: \"--tracking-normal\" },\n      { name: \"wide\", value: \"--tracking-wide\" },\n      { name: \"wider\", value: \"--tracking-wider\" },\n      { name: \"widest\", value: \"--tracking-widest\" },\n    ],\n  },\n};\n",
      "type": "registry:component"
    }
  ],
  "categories": [
    "utility",
    "collection",
    "storybook"
  ],
  "type": "registry:component"
}