23 lines
15 KiB
JSON
23 lines
15 KiB
JSON
{
|
|
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
"name": "radix-dropdown-menu",
|
|
"type": "registry:ui",
|
|
"title": "Dropdown Menu",
|
|
"description": "Displays a menu to the user — such as a set of actions or functions — triggered by a button.",
|
|
"dependencies": [
|
|
"motion",
|
|
"lucide-react",
|
|
"radix-ui"
|
|
],
|
|
"registryDependencies": [
|
|
"https://animate-ui.com/r/motion-highlight"
|
|
],
|
|
"files": [
|
|
{
|
|
"path": "registry/radix/dropdown-menu/index.tsx",
|
|
"content": "'use client';\n\nimport * as React from 'react';\nimport { DropdownMenu as DropdownMenuPrimitive } from 'radix-ui';\nimport { Check, ChevronRight, Circle } from 'lucide-react';\nimport {\n AnimatePresence,\n motion,\n type HTMLMotionProps,\n type Transition,\n} from 'motion/react';\n\nimport { cn } from '@/lib/utils';\nimport {\n MotionHighlight,\n MotionHighlightItem,\n} from '@/components/animate-ui/effects/motion-highlight';\n\ntype DropdownMenuContextType = {\n isOpen: boolean;\n highlightTransition: Transition;\n animateOnHover: boolean;\n};\n\nconst DropdownMenuContext = React.createContext<\n DropdownMenuContextType | undefined\n>(undefined);\n\nconst useDropdownMenu = (): DropdownMenuContextType => {\n const context = React.useContext(DropdownMenuContext);\n if (!context) {\n throw new Error('useDropdownMenu must be used within a DropdownMenu');\n }\n return context;\n};\n\ntype DropdownMenuProps = React.ComponentProps<\n typeof DropdownMenuPrimitive.Root\n> & {\n transition?: Transition;\n animateOnHover?: boolean;\n};\n\nfunction DropdownMenu({\n children,\n transition = { type: 'spring', stiffness: 350, damping: 35 },\n animateOnHover = true,\n ...props\n}: DropdownMenuProps) {\n const [isOpen, setIsOpen] = React.useState(\n props?.open ?? props?.defaultOpen ?? false,\n );\n\n React.useEffect(() => {\n if (props?.open !== undefined) setIsOpen(props.open);\n }, [props?.open]);\n\n const handleOpenChange = React.useCallback(\n (open: boolean) => {\n setIsOpen(open);\n props.onOpenChange?.(open);\n },\n [props],\n );\n\n return (\n <DropdownMenuContext.Provider\n value={{ isOpen, highlightTransition: transition, animateOnHover }}\n >\n <DropdownMenuPrimitive.Root\n data-slot=\"dropdown-menu\"\n {...props}\n onOpenChange={handleOpenChange}\n >\n {children}\n </DropdownMenuPrimitive.Root>\n </DropdownMenuContext.Provider>\n );\n}\n\ntype DropdownMenuTriggerProps = React.ComponentProps<\n typeof DropdownMenuPrimitive.Trigger\n>;\n\nfunction DropdownMenuTrigger(props: DropdownMenuTriggerProps) {\n return (\n <DropdownMenuPrimitive.Trigger\n data-slot=\"dropdown-menu-trigger\"\n {...props}\n />\n );\n}\n\ntype DropdownMenuGroupProps = React.ComponentProps<\n typeof DropdownMenuPrimitive.Group\n>;\n\nfunction DropdownMenuGroup(props: DropdownMenuGroupProps) {\n return (\n <DropdownMenuPrimitive.Group data-slot=\"dropdown-menu-group\" {...props} />\n );\n}\n\ntype DropdownMenuPortalProps = React.ComponentProps<\n typeof DropdownMenuPrimitive.Portal\n>;\n\nfunction DropdownMenuPortal(props: DropdownMenuPortalProps) {\n return (\n <DropdownMenuPrimitive.Portal data-slot=\"dropdown-menu-portal\" {...props} />\n );\n}\n\ntype DropdownMenuSubProps = React.ComponentProps<\n typeof DropdownMenuPrimitive.Sub\n>;\n\nfunction DropdownMenuSub(props: DropdownMenuSubProps) {\n return <DropdownMenuPrimitive.Sub data-slot=\"dropdown-menu-sub\" {...props} />;\n}\n\ntype DropdownMenuRadioGroupProps = React.ComponentProps<\n typeof DropdownMenuPrimitive.RadioGroup\n>;\n\nfunction DropdownMenuRadioGroup(props: DropdownMenuRadioGroupProps) {\n return (\n <DropdownMenuPrimitive.RadioGroup\n data-slot=\"dropdown-menu-radio-group\"\n {...props}\n />\n );\n}\n\ntype DropdownMenuSubTriggerProps = React.ComponentProps<\n typeof DropdownMenuPrimitive.SubTrigger\n> & {\n inset?: boolean;\n};\n\nfunction DropdownMenuSubTrigger({\n className,\n children,\n inset,\n disabled,\n ...props\n}: DropdownMenuSubTriggerProps) {\n return (\n <MotionHighlightItem disabled={disabled}>\n <DropdownMenuPrimitive.SubTrigger {...props} disabled={disabled} asChild>\n <motion.div\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset}\n data-disabled={disabled}\n whileTap={{ scale: 0.95 }}\n className={cn(\n \"[&:not([data-highlight])]:focus:bg-accent focus:text-accent-foreground [&:not([data-highlight])]:data-[state=open]:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:[&_[data-chevron]]:rotate-90 [&_[data-chevron]]:transition-transform [&_[data-chevron]]:duration-150 [&_[data-chevron]]:ease-in-out [&_svg:not([class*='text-'])]:text-muted-foreground relative z-[1] flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n inset && 'pl-8',\n className,\n )}\n >\n {children}\n <ChevronRight data-chevron className=\"ml-auto\" />\n </motion.div>\n </DropdownMenuPrimitive.SubTrigger>\n </MotionHighlightItem>\n );\n}\n\ntype DropdownMenuSubContentProps = React.ComponentProps<\n typeof DropdownMenuPrimitive.SubContent\n>;\n\nfunction DropdownMenuSubContent({\n className,\n ...props\n}: DropdownMenuSubContentProps) {\n return (\n <DropdownMenuPrimitive.SubContent\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(\n 'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]',\n className,\n )}\n {...props}\n />\n );\n}\n\ntype DropdownMenuContentProps = React.ComponentProps<\n typeof DropdownMenuPrimitive.Content\n> &\n HTMLMotionProps<'div'> & {\n transition?: Transition;\n };\n\nfunction DropdownMenuContent({\n className,\n children,\n sideOffset = 4,\n transition = { duration: 0.2 },\n ...props\n}: DropdownMenuContentProps) {\n const { isOpen, highlightTransition, animateOnHover } = useDropdownMenu();\n\n return (\n <AnimatePresence>\n {isOpen && (\n <DropdownMenuPrimitive.Portal\n forceMount\n data-slot=\"dropdown-menu-portal\"\n >\n <DropdownMenuPrimitive.Content\n sideOffset={sideOffset}\n asChild\n {...props}\n >\n <motion.div\n key=\"dropdown-menu-content\"\n data-slot=\"dropdown-menu-content\"\n className={cn(\n 'z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]',\n className,\n )}\n initial={{\n opacity: 0,\n scale: 0.95,\n }}\n animate={{\n opacity: 1,\n scale: 1,\n }}\n exit={{\n opacity: 0,\n scale: 0.95,\n }}\n transition={transition}\n style={{ willChange: 'opacity, transform' }}\n {...props}\n >\n <MotionHighlight\n hover\n className=\"rounded-sm\"\n controlledItems\n transition={highlightTransition}\n enabled={animateOnHover}\n >\n {children}\n </MotionHighlight>\n </motion.div>\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n )}\n </AnimatePresence>\n );\n}\n\ntype DropdownMenuItemProps = React.ComponentProps<\n typeof DropdownMenuPrimitive.Item\n> & {\n inset?: boolean;\n variant?: 'default' | 'destructive';\n};\n\nfunction DropdownMenuItem({\n className,\n children,\n inset,\n disabled,\n variant = 'default',\n ...props\n}: DropdownMenuItemProps) {\n return (\n <MotionHighlightItem\n activeClassName={\n variant === 'default'\n ? 'bg-accent'\n : 'bg-destructive/10 dark:bg-destructive/20'\n }\n disabled={disabled}\n >\n <DropdownMenuPrimitive.Item {...props} disabled={disabled} asChild>\n <motion.div\n data-slot=\"dropdown-menu-item\"\n data-inset={inset}\n data-variant={variant}\n data-disabled={disabled}\n whileTap={{ scale: 0.95 }}\n className={cn(\n \"[&:not([data-highlight])]:focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive [&:not([data-highlight])]:data-[variant=destructive]:focus:bg-destructive/10 dark:[&:not([data-highlight])]:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative z-[1] flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus-visible:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n inset && 'pl-8',\n className,\n )}\n >\n {children}\n </motion.div>\n </DropdownMenuPrimitive.Item>\n </MotionHighlightItem>\n );\n}\n\ntype DropdownMenuCheckboxItemProps = React.ComponentProps<\n typeof DropdownMenuPrimitive.CheckboxItem\n>;\n\nfunction DropdownMenuCheckboxItem({\n className,\n children,\n checked,\n disabled,\n ...props\n}: DropdownMenuCheckboxItemProps) {\n return (\n <MotionHighlightItem disabled={disabled}>\n <DropdownMenuPrimitive.CheckboxItem\n {...props}\n checked={checked}\n disabled={disabled}\n asChild\n >\n <motion.div\n data-slot=\"dropdown-menu-checkbox-item\"\n data-disabled={disabled}\n whileTap={{ scale: 0.95 }}\n className={cn(\n \"[&:not([data-highlight])]:focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n >\n <span className=\"absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator data-slot=\"dropdown-menu-checkbox-item-indicator\">\n <Check className=\"size-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </motion.div>\n </DropdownMenuPrimitive.CheckboxItem>\n </MotionHighlightItem>\n );\n}\n\ntype DropdownMenuRadioItemProps = React.ComponentProps<\n typeof DropdownMenuPrimitive.RadioItem\n>;\n\nfunction DropdownMenuRadioItem({\n className,\n children,\n disabled,\n ...props\n}: DropdownMenuRadioItemProps) {\n return (\n <MotionHighlightItem disabled={disabled}>\n <DropdownMenuPrimitive.RadioItem {...props} disabled={disabled} asChild>\n <motion.div\n data-slot=\"dropdown-menu-radio-item\"\n data-disabled={disabled}\n whileTap={{ scale: 0.95 }}\n className={cn(\n \"[&:not([data-highlight])]:focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator data-slot=\"dropdown-menu-radio-item-indicator\">\n <Circle className=\"size-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </motion.div>\n </DropdownMenuPrimitive.RadioItem>\n </MotionHighlightItem>\n );\n}\n\ntype DropdownMenuLabelProps = React.ComponentProps<\n typeof DropdownMenuPrimitive.Label\n> & {\n inset?: boolean;\n};\n\nfunction DropdownMenuLabel({\n className,\n inset,\n ...props\n}: DropdownMenuLabelProps) {\n return (\n <DropdownMenuPrimitive.Label\n data-slot=\"dropdown-menu-label\"\n data-inset={inset}\n className={cn(\n 'px-2 py-1.5 text-sm font-semibold',\n inset && 'pl-8',\n className,\n )}\n {...props}\n />\n );\n}\n\ntype DropdownMenuSeparatorProps = React.ComponentProps<\n typeof DropdownMenuPrimitive.Separator\n>;\n\nfunction DropdownMenuSeparator({\n className,\n ...props\n}: DropdownMenuSeparatorProps) {\n return (\n <DropdownMenuPrimitive.Separator\n data-slot=\"dropdown-menu-separator\"\n className={cn('-mx-1 my-1 h-px bg-border', className)}\n {...props}\n />\n );\n}\n\ntype DropdownMenuShortcutProps = React.ComponentProps<'span'>;\n\nfunction DropdownMenuShortcut({\n className,\n ...props\n}: DropdownMenuShortcutProps) {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn(\n 'text-muted-foreground ml-auto text-xs tracking-widest',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuGroup,\n DropdownMenuPortal,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuRadioGroup,\n type DropdownMenuProps,\n type DropdownMenuTriggerProps,\n type DropdownMenuContentProps,\n type DropdownMenuItemProps,\n type DropdownMenuCheckboxItemProps,\n type DropdownMenuRadioItemProps,\n type DropdownMenuLabelProps,\n type DropdownMenuSeparatorProps,\n type DropdownMenuShortcutProps,\n type DropdownMenuGroupProps,\n type DropdownMenuPortalProps,\n type DropdownMenuSubProps,\n type DropdownMenuSubContentProps,\n type DropdownMenuSubTriggerProps,\n type DropdownMenuRadioGroupProps,\n};\n",
|
|
"type": "registry:ui",
|
|
"target": "components/animate-ui/radix/dropdown-menu.tsx"
|
|
}
|
|
]
|
|
} |