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 ( )