diff --git a/web/src/components/ui/menu.stories.tsx b/web/src/components/ui/menu.stories.tsx new file mode 100644 index 0000000..e6d622c --- /dev/null +++ b/web/src/components/ui/menu.stories.tsx @@ -0,0 +1,32 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { expect, within } from 'storybook/test' + +import { Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger } from './menu' +import { Button } from './button' + +const meta = { + component: Menu, + tags: ['ai-generated'], +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = { + render: () => ( + + Open} /> + + First + + Second + + + ), + play: async ({ canvas, userEvent }) => { + await userEvent.click(canvas.getByRole('button', { name: 'Open' })) + await expect( + await within(document.body).findByText('First'), + ).toBeInTheDocument() + }, +} diff --git a/web/src/components/ui/menu.tsx b/web/src/components/ui/menu.tsx new file mode 100644 index 0000000..b0a4d3d --- /dev/null +++ b/web/src/components/ui/menu.tsx @@ -0,0 +1,67 @@ +import { Menu as MenuPrimitive } from "@base-ui/react/menu" + +import { cn } from "@/lib/utils" + +function Menu({ ...props }: MenuPrimitive.Root.Props) { + return +} + +function MenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) { + return +} + +function MenuContent({ + className, + sideOffset = 6, + align = "end", + ...props +}: MenuPrimitive.Popup.Props & { + sideOffset?: MenuPrimitive.Positioner.Props["sideOffset"] + align?: MenuPrimitive.Positioner.Props["align"] +}) { + return ( + + + + + + ) +} + +function MenuItem({ className, ...props }: MenuPrimitive.Item.Props) { + return ( + + ) +} + +function MenuSeparator({ className, ...props }: MenuPrimitive.Separator.Props) { + return ( + + ) +} + +export { Menu, MenuTrigger, MenuContent, MenuItem, MenuSeparator }