{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "profile-menu",
  "title": "Profile Menu",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/profile-menu/ProfileMenu.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport { BadgeCheck, Bell, CreditCard, LogOut, Sparkles, Settings } from 'lucide-react'\nimport { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu'\n\ninterface User {\n  name: string\n  email: string\n  avatar?: string\n}\n\ntype ProfileMenuKey = 'upgrade' | 'account' | 'billing' | 'notifications' | 'settings' | 'logout'\n\nexport interface ProfileMenuProps {\n  user?: User\n  /** Custom trigger. Receives the resolved user + computed initials. When\n   *  omitted, a default avatar button is rendered. */\n  trigger?: (ctx: { user: User; initials: string }) => React.ReactNode\n  onSelect?: (key: ProfileMenuKey) => void\n}\n\nexport function ProfileMenu({\n  user = { name: 'Alex Morgan', email: 'alex@example.com', avatar: '' },\n  trigger,\n  onSelect,\n}: ProfileMenuProps) {\n  const initials = React.useMemo(() => {\n    const parts = user.name.trim().split(/\\s+/).slice(0, 2)\n    return parts.map((p) => p[0]?.toUpperCase()).join('') || 'U'\n  }, [user.name])\n\n  return (\n    <DropdownMenu>\n      <DropdownMenuTrigger asChild>\n        {trigger ? (\n          trigger({ user, initials })\n        ) : (\n          <button\n            type=\"button\"\n            className=\"hover:bg-accent focus-visible:ring-ring flex size-8 items-center justify-center rounded-lg transition-colors focus-visible:ring-1 focus-visible:outline-none\"\n            aria-label=\"Open profile menu\"\n          >\n            <Avatar className=\"size-7\">\n              {user.avatar ? <AvatarImage src={user.avatar} alt={user.name} /> : null}\n              <AvatarFallback className=\"bg-primary/10 text-primary text-[11px] font-semibold\">\n                {initials}\n              </AvatarFallback>\n            </Avatar>\n          </button>\n        )}\n      </DropdownMenuTrigger>\n      <DropdownMenuContent className=\"w-60 rounded-lg\" align=\"end\" sideOffset={8}>\n        <DropdownMenuLabel className=\"p-0 font-normal\">\n          <div className=\"flex items-center gap-2 px-1 py-1.5 text-left text-sm\">\n            <Avatar className=\"size-9 rounded-lg\">\n              {user.avatar ? <AvatarImage src={user.avatar} alt={user.name} /> : null}\n              <AvatarFallback className=\"bg-primary/10 text-primary rounded-lg text-xs font-semibold\">\n                {initials}\n              </AvatarFallback>\n            </Avatar>\n            <div className=\"grid flex-1 text-left leading-tight\">\n              <span className=\"truncate text-sm font-semibold\">{user.name}</span>\n              <span className=\"text-muted-foreground truncate text-xs\">{user.email}</span>\n            </div>\n          </div>\n        </DropdownMenuLabel>\n        <DropdownMenuSeparator />\n        <DropdownMenuGroup>\n          <DropdownMenuItem onSelect={() => onSelect?.('upgrade')}>\n            <Sparkles className=\"size-4\" />\n            Upgrade to Pro\n          </DropdownMenuItem>\n        </DropdownMenuGroup>\n        <DropdownMenuSeparator />\n        <DropdownMenuGroup>\n          <DropdownMenuItem onSelect={() => onSelect?.('account')}>\n            <BadgeCheck className=\"size-4\" />\n            Account\n          </DropdownMenuItem>\n          <DropdownMenuItem onSelect={() => onSelect?.('billing')}>\n            <CreditCard className=\"size-4\" />\n            Billing\n          </DropdownMenuItem>\n          <DropdownMenuItem onSelect={() => onSelect?.('notifications')}>\n            <Bell className=\"size-4\" />\n            Notifications\n          </DropdownMenuItem>\n          <DropdownMenuItem onSelect={() => onSelect?.('settings')}>\n            <Settings className=\"size-4\" />\n            Settings\n          </DropdownMenuItem>\n        </DropdownMenuGroup>\n        <DropdownMenuSeparator />\n        <DropdownMenuItem onSelect={() => onSelect?.('logout')}>\n          <LogOut className=\"size-4\" />\n          Log out\n        </DropdownMenuItem>\n      </DropdownMenuContent>\n    </DropdownMenu>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/ProfileMenu.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/avatar.json",
    "https://uipkge.dev/r/react/dropdown-menu.json"
  ],
  "description": "Header-grade profile/account dropdown. Slot-trigger DropdownMenu the consumer wraps around their own avatar button (default trigger ships an Avatar fallback). Sections: upgrade, account/billing/notifications/settings, log out. Emits `select` with the chosen item key so consumers wire navigation and auth themselves.",
  "categories": [
    "dashboard",
    "overlay"
  ]
}