context-menu.tsx 7.1 KB

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