dropdown-menu.tsx 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import * as React from 'react'
  2. import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
  3. import { Check, ChevronRight, Circle } from 'lucide-react'
  4. import { cn } from '@/lib/utils'
  5. const DropdownMenu = DropdownMenuPrimitive.Root
  6. const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
  7. const DropdownMenuGroup = DropdownMenuPrimitive.Group
  8. const DropdownMenuPortal = DropdownMenuPrimitive.Portal
  9. const DropdownMenuSub = DropdownMenuPrimitive.Sub
  10. const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
  11. const DropdownMenuSubTrigger = React.forwardRef<
  12. React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
  13. React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
  14. inset?: boolean
  15. }
  16. >(({ className, inset, children, ...props }, ref) => (
  17. <DropdownMenuPrimitive.SubTrigger
  18. ref={ref}
  19. className={cn(
  20. 'ui__dropdown-menu-sub-trigger',
  21. 'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent',
  22. inset && 'pl-8',
  23. className
  24. )}
  25. {...props}
  26. >
  27. {children}
  28. <ChevronRight className="ml-auto h-4 w-4"/>
  29. </DropdownMenuPrimitive.SubTrigger>
  30. ))
  31. DropdownMenuSubTrigger.displayName =
  32. DropdownMenuPrimitive.SubTrigger.displayName
  33. const DropdownMenuSubContent = React.forwardRef<
  34. React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
  35. React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
  36. >(({ className, ...props }, ref) => (
  37. <DropdownMenuPrimitive.SubContent
  38. ref={ref}
  39. className={cn(
  40. 'ui__dropdown-menu-sub-content',
  41. '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',
  42. className
  43. )}
  44. {...props}
  45. />
  46. ))
  47. DropdownMenuSubContent.displayName =
  48. DropdownMenuPrimitive.SubContent.displayName
  49. const DropdownMenuContent = React.forwardRef<
  50. React.ElementRef<typeof DropdownMenuPrimitive.Content>,
  51. React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
  52. >(({ className, sideOffset = 4, ...props }, ref) => (
  53. <DropdownMenuPrimitive.Portal>
  54. <DropdownMenuPrimitive.Content
  55. ref={ref}
  56. sideOffset={sideOffset}
  57. className={cn(
  58. 'ui__dropdown-menu-content',
  59. 'z-50 min-w-[8rem] overflow-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',
  60. className
  61. )}
  62. {...props}
  63. />
  64. </DropdownMenuPrimitive.Portal>
  65. ))
  66. DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
  67. const DropdownMenuItem = React.forwardRef<
  68. React.ElementRef<typeof DropdownMenuPrimitive.Item>,
  69. React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
  70. inset?: boolean
  71. }
  72. >(({ className, inset, ...props }, ref) => (
  73. <DropdownMenuPrimitive.Item
  74. ref={ref}
  75. className={cn(
  76. 'ui__dropdown-menu-item',
  77. 'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
  78. inset && 'pl-8',
  79. className
  80. )}
  81. {...props}
  82. />
  83. ))
  84. DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
  85. const DropdownMenuCheckboxItem = React.forwardRef<
  86. React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
  87. React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
  88. >(({ className, children, checked, ...props }, ref) => (
  89. <DropdownMenuPrimitive.CheckboxItem
  90. ref={ref}
  91. className={cn(
  92. 'ui__dropdown-menu-checkbox-item',
  93. 'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
  94. className
  95. )}
  96. checked={checked}
  97. {...props}
  98. >
  99. <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
  100. <DropdownMenuPrimitive.ItemIndicator>
  101. <Check className="h-4 w-4"/>
  102. </DropdownMenuPrimitive.ItemIndicator>
  103. </span>
  104. {children}
  105. </DropdownMenuPrimitive.CheckboxItem>
  106. ))
  107. DropdownMenuCheckboxItem.displayName =
  108. DropdownMenuPrimitive.CheckboxItem.displayName
  109. const DropdownMenuRadioItem = React.forwardRef<
  110. React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
  111. React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
  112. >(({ className, children, ...props }, ref) => (
  113. <DropdownMenuPrimitive.RadioItem
  114. ref={ref}
  115. className={cn(
  116. 'ui__dropdown-menu-radio-item',
  117. 'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
  118. className
  119. )}
  120. {...props}
  121. >
  122. <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
  123. <DropdownMenuPrimitive.ItemIndicator>
  124. <Circle className="h-2 w-2 fill-current"/>
  125. </DropdownMenuPrimitive.ItemIndicator>
  126. </span>
  127. {children}
  128. </DropdownMenuPrimitive.RadioItem>
  129. ))
  130. DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
  131. const DropdownMenuLabel = React.forwardRef<
  132. React.ElementRef<typeof DropdownMenuPrimitive.Label>,
  133. React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
  134. inset?: boolean
  135. }
  136. >(({ className, inset, ...props }, ref) => (
  137. <DropdownMenuPrimitive.Label
  138. ref={ref}
  139. className={cn(
  140. 'px-2 py-1.5 text-sm font-semibold',
  141. inset && 'pl-8',
  142. className
  143. )}
  144. {...props}
  145. />
  146. ))
  147. DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
  148. const DropdownMenuSeparator = React.forwardRef<
  149. React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
  150. React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
  151. >(({ className, ...props }, ref) => (
  152. <DropdownMenuPrimitive.Separator
  153. ref={ref}
  154. className={cn('-mx-1 my-1 h-px bg-muted', className)}
  155. {...props}
  156. />
  157. ))
  158. DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
  159. const DropdownMenuShortcut = ({
  160. className,
  161. ...props
  162. }: React.HTMLAttributes<HTMLSpanElement>) => {
  163. return (
  164. <span
  165. className={cn('ml-auto text-xs opacity-60', className)}
  166. {...props}
  167. />
  168. )
  169. }
  170. DropdownMenuShortcut.displayName = 'DropdownMenuShortcut'
  171. export {
  172. DropdownMenu,
  173. DropdownMenuTrigger,
  174. DropdownMenuContent,
  175. DropdownMenuItem,
  176. DropdownMenuCheckboxItem,
  177. DropdownMenuRadioItem,
  178. DropdownMenuLabel,
  179. DropdownMenuSeparator,
  180. DropdownMenuShortcut,
  181. DropdownMenuGroup,
  182. DropdownMenuPortal,
  183. DropdownMenuSub,
  184. DropdownMenuSubContent,
  185. DropdownMenuSubTrigger,
  186. DropdownMenuRadioGroup,
  187. }