{"$schema":"https:\/\/ui.particle.academy\/schema\/registry-item.json","name":"menu","type":"registry:ui","title":"Menu","description":"Menu from react-fancy","package":"react-fancy","dependencies":["lucide-react"],"registryDependencies":[],"files":[{"path":"components\/fancy\/menu\/Menu.context.ts","content":"import { createContext, useContext } from \"react\";\r\nimport type { MenuContextValue } from \".\/Menu.types\";\r\n\r\nexport const MenuContext = createContext<MenuContextValue | null>(null);\r\n\r\nexport function useMenu(): MenuContextValue {\r\n  const ctx = useContext(MenuContext);\r\n  if (!ctx) {\r\n    throw new Error(\"useMenu must be used within a <Menu> component\");\r\n  }\r\n  return ctx;\r\n}\r\n","type":"registry:ui","target":"components\/fancy\/menu\/Menu.context.ts"},{"path":"components\/fancy\/menu\/Menu.tsx","content":"import { cn } from \"..\/..\/utils\/cn\";\r\nimport { MenuContext } from \".\/Menu.context\";\r\nimport { MenuItem } from \".\/MenuItem\";\r\nimport { MenuSubmenu } from \".\/MenuSubmenu\";\r\nimport { MenuGroup } from \".\/MenuGroup\";\r\nimport type { MenuProps } from \".\/Menu.types\";\r\n\r\nfunction MenuRoot({ children, orientation = \"vertical\", className }: MenuProps) {\r\n  const isVertical = orientation === \"vertical\";\r\n\r\n  return (\r\n    <MenuContext.Provider value={{ orientation }}>\r\n      <nav\r\n        data-react-fancy-menu=\"\"\r\n        data-orientation={orientation}\r\n        className={cn(\r\n          \"flex gap-0.5\",\r\n          isVertical ? \"flex-col\" : \"flex-row items-center\",\r\n          className,\r\n        )}\r\n      >\r\n        {children}\r\n      <\/nav>\r\n    <\/MenuContext.Provider>\r\n  );\r\n}\r\n\r\nexport const Menu = Object.assign(MenuRoot, {\r\n  Item: MenuItem,\r\n  Submenu: MenuSubmenu,\r\n  Group: MenuGroup,\r\n});\r\n","type":"registry:ui","target":"components\/fancy\/menu\/Menu.tsx"},{"path":"components\/fancy\/menu\/Menu.types.ts","content":"import type { ReactNode } from \"react\";\r\n\r\nexport type MenuOrientation = \"horizontal\" | \"vertical\";\r\n\r\nexport interface MenuProps {\r\n  children: ReactNode;\r\n  orientation?: MenuOrientation;\r\n  className?: string;\r\n}\r\n\r\nexport interface MenuItemProps {\r\n  children: ReactNode;\r\n  href?: string;\r\n  icon?: ReactNode;\r\n  active?: boolean;\r\n  disabled?: boolean;\r\n  badge?: ReactNode;\r\n  onClick?: () => void;\r\n  className?: string;\r\n}\r\n\r\nexport interface MenuSubmenuProps {\r\n  children: ReactNode;\r\n  label: ReactNode;\r\n  icon?: ReactNode;\r\n  defaultOpen?: boolean;\r\n  className?: string;\r\n}\r\n\r\nexport interface MenuGroupProps {\r\n  children: ReactNode;\r\n  label?: string;\r\n  className?: string;\r\n}\r\n\r\nexport interface MenuContextValue {\r\n  orientation: MenuOrientation;\r\n}\r\n","type":"registry:ui","target":"components\/fancy\/menu\/Menu.types.ts"},{"path":"components\/fancy\/menu\/MenuGroup.tsx","content":"import { cn } from \"..\/..\/utils\/cn\";\r\nimport type { MenuGroupProps } from \".\/Menu.types\";\r\n\r\nexport function MenuGroup({ children, label, className }: MenuGroupProps) {\r\n  return (\r\n    <div data-react-fancy-menu-group=\"\" className={cn(\"py-1\", className)}>\r\n      {label && (\r\n        <p className=\"mb-1 px-3 text-xs font-semibold uppercase tracking-wider text-zinc-400 dark:text-zinc-500\">\r\n          {label}\r\n        <\/p>\r\n      )}\r\n      {children}\r\n    <\/div>\r\n  );\r\n}\r\n\r\nMenuGroup.displayName = \"MenuGroup\";\r\n","type":"registry:ui","target":"components\/fancy\/menu\/MenuGroup.tsx"},{"path":"components\/fancy\/menu\/MenuItem.tsx","content":"import { cn } from \"..\/..\/utils\/cn\";\r\nimport { useMenu } from \".\/Menu.context\";\r\nimport type { MenuItemProps } from \".\/Menu.types\";\r\n\r\nexport function MenuItem({\r\n  children,\r\n  href,\r\n  icon,\r\n  active = false,\r\n  disabled = false,\r\n  badge,\r\n  onClick,\r\n  className,\r\n}: MenuItemProps) {\r\n  const { orientation } = useMenu();\r\n  const isVertical = orientation === \"vertical\";\r\n\r\n  const Tag = href ? \"a\" : \"button\";\r\n  const tagProps = href ? { href } : { type: \"button\" as const, onClick };\r\n\r\n  return (\r\n    <Tag\r\n      {...tagProps}\r\n      data-react-fancy-menu-item=\"\"\r\n      data-active={active || undefined}\r\n      aria-current={active ? \"page\" : undefined}\r\n      aria-disabled={disabled || undefined}\r\n      className={cn(\r\n        \"flex items-center gap-2 rounded-md text-sm font-medium transition-colors\",\r\n        \"outline-none focus-visible:ring-2 focus-visible:ring-blue-500\",\r\n        isVertical ? \"w-full px-3 py-2\" : \"px-3 py-2\",\r\n        active\r\n          ? \"bg-zinc-100 text-zinc-900 dark:bg-zinc-800 dark:text-zinc-100\"\r\n          : \"text-zinc-600 hover:bg-zinc-50 hover:text-zinc-900 dark:text-zinc-400 dark:hover:bg-zinc-800\/50 dark:hover:text-zinc-100\",\r\n        disabled && \"pointer-events-none opacity-50\",\r\n        className,\r\n      )}\r\n    >\r\n      {icon && <span className=\"flex h-5 w-5 shrink-0 items-center justify-center\">{icon}<\/span>}\r\n      <span className=\"flex-1 truncate text-left\">{children}<\/span>\r\n      {badge && <span className=\"shrink-0\">{badge}<\/span>}\r\n    <\/Tag>\r\n  );\r\n}\r\n\r\nMenuItem.displayName = \"MenuItem\";\r\n","type":"registry:ui","target":"components\/fancy\/menu\/MenuItem.tsx"},{"path":"components\/fancy\/menu\/MenuSubmenu.tsx","content":"import { useState } from \"react\";\r\nimport { ChevronDown } from \"lucide-react\";\r\nimport { cn } from \"..\/..\/utils\/cn\";\r\nimport { useMenu } from \".\/Menu.context\";\r\nimport type { MenuSubmenuProps } from \".\/Menu.types\";\r\n\r\nexport function MenuSubmenu({\r\n  children,\r\n  label,\r\n  icon,\r\n  defaultOpen = false,\r\n  className,\r\n}: MenuSubmenuProps) {\r\n  const [open, setOpen] = useState(defaultOpen);\r\n  const { orientation } = useMenu();\r\n  const isVertical = orientation === \"vertical\";\r\n\r\n  if (!isVertical) {\r\n    \/\/ Horizontal submenus use a hover-based dropdown\r\n    return (\r\n      <div\r\n        data-react-fancy-menu-submenu=\"\"\r\n        className={cn(\"group relative\", className)}\r\n      >\r\n        <button\r\n          type=\"button\"\r\n          className={cn(\r\n            \"flex items-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors\",\r\n            \"text-zinc-600 hover:bg-zinc-50 hover:text-zinc-900\",\r\n            \"dark:text-zinc-400 dark:hover:bg-zinc-800\/50 dark:hover:text-zinc-100\",\r\n          )}\r\n        >\r\n          {icon && <span className=\"flex h-5 w-5 shrink-0 items-center justify-center\">{icon}<\/span>}\r\n          <span>{label}<\/span>\r\n          <ChevronDown className=\"h-3.5 w-3.5 opacity-60\" \/>\r\n        <\/button>\r\n        <div\r\n          className={cn(\r\n            \"invisible absolute left-0 top-full z-50 min-w-[180px] pt-1 opacity-0 transition-all\",\r\n            \"group-hover:visible group-hover:opacity-100\",\r\n          )}\r\n        >\r\n          <div className=\"rounded-lg border border-zinc-200 bg-white py-1 shadow-lg dark:border-zinc-700 dark:bg-zinc-900\">\r\n            {children}\r\n          <\/div>\r\n        <\/div>\r\n      <\/div>\r\n    );\r\n  }\r\n\r\n  \/\/ Vertical submenus use accordion-style expand\/collapse\r\n  return (\r\n    <div data-react-fancy-menu-submenu=\"\" className={className}>\r\n      <button\r\n        type=\"button\"\r\n        onClick={() => setOpen((v) => !v)}\r\n        className={cn(\r\n          \"flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors\",\r\n          \"text-zinc-600 hover:bg-zinc-50 hover:text-zinc-900\",\r\n          \"dark:text-zinc-400 dark:hover:bg-zinc-800\/50 dark:hover:text-zinc-100\",\r\n        )}\r\n      >\r\n        {icon && <span className=\"flex h-5 w-5 shrink-0 items-center justify-center\">{icon}<\/span>}\r\n        <span className=\"flex-1 text-left\">{label}<\/span>\r\n        <ChevronDown\r\n          className={cn(\r\n            \"h-3.5 w-3.5 opacity-60 transition-transform duration-200\",\r\n            open && \"rotate-180\",\r\n          )}\r\n        \/>\r\n      <\/button>\r\n      <div\r\n        className={cn(\r\n          \"grid transition-[grid-template-rows] duration-200\",\r\n          open ? \"grid-rows-[1fr]\" : \"grid-rows-[0fr]\",\r\n        )}\r\n      >\r\n        <div className=\"overflow-hidden\">\r\n          <div className=\"ml-4 border-l border-zinc-200 pl-2 pt-1 dark:border-zinc-700\">\r\n            {children}\r\n          <\/div>\r\n        <\/div>\r\n      <\/div>\r\n    <\/div>\r\n  );\r\n}\r\n\r\nMenuSubmenu.displayName = \"MenuSubmenu\";\r\n","type":"registry:ui","target":"components\/fancy\/menu\/MenuSubmenu.tsx"},{"path":"components\/fancy\/menu\/index.ts","content":"export { Menu } from \".\/Menu\";\r\nexport { useMenu } from \".\/Menu.context\";\r\nexport type {\r\n  MenuProps,\r\n  MenuItemProps,\r\n  MenuSubmenuProps,\r\n  MenuGroupProps,\r\n  MenuOrientation,\r\n  MenuContextValue,\r\n} from \".\/Menu.types\";\r\n","type":"registry:ui","target":"components\/fancy\/menu\/index.ts"}]}