From dbaf22500ef3c84cbead61b40c985fc762ba44da Mon Sep 17 00:00:00 2001 From: Anders Olsson Date: Sun, 7 Jun 2026 19:05:25 +0200 Subject: [PATCH] feat(web): ui/menu Base UI dropdown wrapper + story (#54) --- web/src/components/ui/menu.stories.tsx | 32 ++++++++++++ web/src/components/ui/menu.tsx | 67 ++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 web/src/components/ui/menu.stories.tsx create mode 100644 web/src/components/ui/menu.tsx 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 }