select.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. "use client"
  2. import * as React from "react"
  3. import { Select as SelectPrimitive } from "@base-ui/react/select"
  4. import { Check, ChevronDown } from "lucide-react"
  5. import { cn } from "@/lib/utils/client"
  6. const Select = SelectPrimitive.Root
  7. const SelectGroup = SelectPrimitive.Group
  8. const SelectValue = SelectPrimitive.Value
  9. const SelectTrigger = React.forwardRef<
  10. HTMLButtonElement,
  11. React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
  12. >(({ className, children, ...props }, ref) => (
  13. <SelectPrimitive.Trigger
  14. ref={ref}
  15. className={cn(
  16. "flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm data-[placeholder]:text-muted-foreground focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
  17. className
  18. )}
  19. {...props}
  20. >
  21. {children}
  22. <SelectPrimitive.Icon>
  23. <ChevronDown className="h-4 w-4 opacity-50" />
  24. </SelectPrimitive.Icon>
  25. </SelectPrimitive.Trigger>
  26. ))
  27. SelectTrigger.displayName = "SelectTrigger"
  28. const SelectContent = React.forwardRef<
  29. HTMLDivElement,
  30. React.ComponentPropsWithoutRef<typeof SelectPrimitive.Popup>
  31. >(({ className, children, ...props }, ref) => (
  32. <SelectPrimitive.Portal>
  33. <SelectPrimitive.Positioner>
  34. <SelectPrimitive.Popup
  35. ref={ref}
  36. className={cn(
  37. "relative z-50 max-h-96 min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[open]:animate-in data-[closed]:animate-out data-[closed]:fade-out-0 data-[open]:fade-in-0 data-[closed]:zoom-out-95 data-[open]:zoom-in-95",
  38. className
  39. )}
  40. {...props}
  41. >
  42. <SelectPrimitive.List className="p-1">
  43. {children}
  44. </SelectPrimitive.List>
  45. </SelectPrimitive.Popup>
  46. </SelectPrimitive.Positioner>
  47. </SelectPrimitive.Portal>
  48. ))
  49. SelectContent.displayName = "SelectContent"
  50. const SelectLabel = React.forwardRef<
  51. HTMLDivElement,
  52. React.ComponentPropsWithoutRef<typeof SelectPrimitive.GroupLabel>
  53. >(({ className, ...props }, ref) => (
  54. <SelectPrimitive.GroupLabel
  55. ref={ref}
  56. className={cn("px-2 py-1.5 text-sm font-semibold", className)}
  57. {...props}
  58. />
  59. ))
  60. SelectLabel.displayName = "SelectLabel"
  61. const SelectItem = React.forwardRef<
  62. HTMLDivElement,
  63. React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
  64. >(({ className, children, ...props }, ref) => (
  65. <SelectPrimitive.Item
  66. ref={ref}
  67. className={cn(
  68. "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
  69. className
  70. )}
  71. {...props}
  72. >
  73. <span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
  74. <SelectPrimitive.ItemIndicator>
  75. <Check className="h-4 w-4" />
  76. </SelectPrimitive.ItemIndicator>
  77. </span>
  78. <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
  79. </SelectPrimitive.Item>
  80. ))
  81. SelectItem.displayName = "SelectItem"
  82. const SelectSeparator = React.forwardRef<
  83. HTMLDivElement,
  84. React.HTMLAttributes<HTMLDivElement>
  85. >(({ className, ...props }, ref) => (
  86. <div
  87. ref={ref}
  88. className={cn("-mx-1 my-1 h-px bg-muted", className)}
  89. {...props}
  90. />
  91. ))
  92. SelectSeparator.displayName = "SelectSeparator"
  93. export {
  94. Select,
  95. SelectGroup,
  96. SelectValue,
  97. SelectTrigger,
  98. SelectContent,
  99. SelectLabel,
  100. SelectItem,
  101. SelectSeparator,
  102. }