From 477bf6e0758eb7717bfbe1dac05e686c173a3be3 Mon Sep 17 00:00:00 2001
From: yyh <92089059+lyzno1@users.noreply.github.com>
Date: Wed, 4 Mar 2026 09:53:15 +0800
Subject: [PATCH] fix(web): align dropdown-menu styles with Figma design
(#32922)
---
.../base/ui/dropdown-menu/index.stories.tsx | 317 ++++++++++++++++++
.../base/ui/dropdown-menu/index.tsx | 12 +-
2 files changed, 323 insertions(+), 6 deletions(-)
create mode 100644 web/app/components/base/ui/dropdown-menu/index.stories.tsx
diff --git a/web/app/components/base/ui/dropdown-menu/index.stories.tsx b/web/app/components/base/ui/dropdown-menu/index.stories.tsx
new file mode 100644
index 0000000000..70afc07819
--- /dev/null
+++ b/web/app/components/base/ui/dropdown-menu/index.stories.tsx
@@ -0,0 +1,317 @@
+import type { Meta, StoryObj } from '@storybook/nextjs-vite'
+import { useState } from 'react'
+import {
+ DropdownMenu,
+ DropdownMenuCheckboxItem,
+ DropdownMenuCheckboxItemIndicator,
+ DropdownMenuContent,
+ DropdownMenuGroup,
+ DropdownMenuGroupLabel,
+ DropdownMenuItem,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuRadioItemIndicator,
+ DropdownMenuSeparator,
+ DropdownMenuSub,
+ DropdownMenuSubContent,
+ DropdownMenuSubTrigger,
+ DropdownMenuTrigger,
+} from '.'
+
+const TriggerButton = ({ label = 'Open Menu' }: { label?: string }) => (
+ }
+ >
+ {label}
+
+)
+
+const meta = {
+ title: 'Base/Navigation/DropdownMenu',
+ component: DropdownMenu,
+ parameters: {
+ layout: 'centered',
+ docs: {
+ description: {
+ component: 'Compound dropdown menu built on Base UI Menu. Supports items, separators, group labels, submenus, radio groups, checkbox items, destructive items, and disabled states.',
+ },
+ },
+ },
+ tags: ['autodocs'],
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const Default: Story = {
+ render: () => (
+
+
+
+ Edit
+ Duplicate
+ Archive
+
+
+ ),
+}
+
+export const WithSeparator: Story = {
+ render: () => (
+
+
+
+ Cut
+ Copy
+ Paste
+
+ Select All
+
+ Find and Replace
+
+
+ ),
+}
+
+export const WithGroupLabel: Story = {
+ render: () => (
+
+
+
+
+ Actions
+ Edit
+ Duplicate
+
+
+
+ Export
+ Export as PDF
+ Export as CSV
+
+
+
+ ),
+}
+
+export const WithDestructiveItem: Story = {
+ render: () => (
+
+
+
+ Edit
+ Duplicate
+
+ Delete
+
+
+ ),
+}
+
+export const WithSubmenu: Story = {
+ render: () => (
+
+
+
+ New File
+ Open
+
+
+ Share
+
+ Email
+ Slack
+ Copy Link
+
+
+
+ Download
+
+
+ ),
+}
+
+const WithRadioItemsDemo = () => {
+ const [value, setValue] = useState('comfortable')
+
+ return (
+
+
+
+
+
+ Compact
+
+
+
+ Comfortable
+
+
+
+ Spacious
+
+
+
+
+
+ )
+}
+
+export const WithRadioItems: Story = {
+ render: () => ,
+}
+
+const WithCheckboxItemsDemo = () => {
+ const [showToolbar, setShowToolbar] = useState(true)
+ const [showSidebar, setShowSidebar] = useState(false)
+ const [showStatusBar, setShowStatusBar] = useState(true)
+
+ return (
+
+
+
+
+ Toolbar
+
+
+
+ Sidebar
+
+
+
+ Status Bar
+
+
+
+
+ )
+}
+
+export const WithCheckboxItems: Story = {
+ render: () => ,
+}
+
+export const WithDisabledItems: Story = {
+ render: () => (
+
+
+
+ Edit
+ Duplicate
+ Archive
+
+ Restore
+ Delete
+
+
+ ),
+}
+
+export const WithIcons: Story = {
+ render: () => (
+
+
+
+
+
+ Edit
+
+
+
+ Duplicate
+
+
+
+ Archive
+
+
+
+
+ Delete
+
+
+
+ ),
+}
+
+const ComplexDemo = () => {
+ const [sortOrder, setSortOrder] = useState('newest')
+ const [showArchived, setShowArchived] = useState(false)
+
+ return (
+
+
+
+
+ Edit
+
+
+ Rename
+
+
+
+ Duplicate
+
+
+
+ Move to Workspace
+
+
+
+
+
+
+ Share
+
+
+
+
+ Email
+
+
+
+ Slack
+
+
+
+ Copy Link
+
+
+
+
+
+ Sort by
+
+
+ Newest first
+
+
+
+ Oldest first
+
+
+
+ Name
+
+
+
+
+
+
+
+ Show Archived
+
+
+
+
+
+ Delete
+
+
+
+ )
+}
+
+export const Complex: Story = {
+ render: () => ,
+}
diff --git a/web/app/components/base/ui/dropdown-menu/index.tsx b/web/app/components/base/ui/dropdown-menu/index.tsx
index e839fd24ef..8d4f630adc 100644
--- a/web/app/components/base/ui/dropdown-menu/index.tsx
+++ b/web/app/components/base/ui/dropdown-menu/index.tsx
@@ -13,8 +13,8 @@ export const DropdownMenuSub = Menu.SubmenuRoot
export const DropdownMenuGroup = Menu.Group
export const DropdownMenuRadioGroup = Menu.RadioGroup
-const menuRowBaseClassName = 'mx-1 flex h-8 cursor-pointer select-none items-center rounded-lg px-2 outline-none'
-const menuRowStateClassName = 'data-[highlighted]:bg-state-base-hover data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50'
+const menuRowBaseClassName = 'mx-1 flex h-8 cursor-pointer select-none items-center gap-1 rounded-lg px-2 outline-none'
+const menuRowStateClassName = 'data-[highlighted]:bg-state-base-hover data-[disabled]:cursor-not-allowed data-[disabled]:opacity-30'
export function DropdownMenuRadioItem({
className,
@@ -89,7 +89,7 @@ export function DropdownMenuGroupLabel({
return (
{children}
-
+
)
}
@@ -270,7 +270,7 @@ export function DropdownMenuSeparator({
}: React.ComponentPropsWithoutRef) {
return (
)