select.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. "use client";
  2. import * as React from "react";
  3. import { Select as SelectPrimitive } from "radix-ui";
  4. import { Check, ChevronDown, ChevronUp } from "lucide-react";
  5. import { cn } from "@/lib/utils";
  6. const Select = SelectPrimitive.Root;
  7. const SelectGroup = SelectPrimitive.Group;
  8. const SelectValue = SelectPrimitive.Value;
  9. const SelectTrigger = React.forwardRef<
  10. React.ComponentRef<typeof SelectPrimitive.Trigger>,
  11. React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
  12. >(({ className, children, ...props }, ref) => (
  13. <SelectPrimitive.Trigger
  14. ref={ref}
  15. className={cn(
  16. "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
  17. className,
  18. )}
  19. {...props}
  20. >
  21. {children}
  22. <SelectPrimitive.Icon asChild>
  23. <ChevronDown className="h-4 w-4 opacity-50" />
  24. </SelectPrimitive.Icon>
  25. </SelectPrimitive.Trigger>
  26. ));
  27. SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
  28. const SelectScrollUpButton = React.forwardRef<
  29. React.ComponentRef<typeof SelectPrimitive.ScrollUpButton>,
  30. React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
  31. >(({ className, ...props }, ref) => (
  32. <SelectPrimitive.ScrollUpButton
  33. ref={ref}
  34. className={cn(
  35. "flex cursor-default items-center justify-center py-1",
  36. className,
  37. )}
  38. {...props}
  39. >
  40. <ChevronUp className="h-4 w-4" />
  41. </SelectPrimitive.ScrollUpButton>
  42. ));
  43. SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
  44. const SelectScrollDownButton = React.forwardRef<
  45. React.ComponentRef<typeof SelectPrimitive.ScrollDownButton>,
  46. React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
  47. >(({ className, ...props }, ref) => (
  48. <SelectPrimitive.ScrollDownButton
  49. ref={ref}
  50. className={cn(
  51. "flex cursor-default items-center justify-center py-1",
  52. className,
  53. )}
  54. {...props}
  55. >
  56. <ChevronDown className="h-4 w-4" />
  57. </SelectPrimitive.ScrollDownButton>
  58. ));
  59. SelectScrollDownButton.displayName =
  60. SelectPrimitive.ScrollDownButton.displayName;
  61. const SelectContent = React.forwardRef<
  62. React.ComponentRef<typeof SelectPrimitive.Content>,
  63. React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
  64. >(({ className, children, position = "popper", ...props }, ref) => (
  65. <SelectPrimitive.Portal>
  66. <SelectPrimitive.Content
  67. ref={ref}
  68. className={cn(
  69. "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover 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",
  70. position === "popper" &&
  71. "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
  72. className,
  73. )}
  74. position={position}
  75. {...props}
  76. >
  77. <SelectScrollUpButton />
  78. <SelectPrimitive.Viewport
  79. className={cn(
  80. "p-1",
  81. position === "popper" &&
  82. "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
  83. )}
  84. >
  85. {children}
  86. </SelectPrimitive.Viewport>
  87. <SelectScrollDownButton />
  88. </SelectPrimitive.Content>
  89. </SelectPrimitive.Portal>
  90. ));
  91. SelectContent.displayName = SelectPrimitive.Content.displayName;
  92. const SelectItem = React.forwardRef<
  93. React.ComponentRef<typeof SelectPrimitive.Item>,
  94. React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
  95. >(({ className, children, ...props }, ref) => (
  96. <SelectPrimitive.Item
  97. ref={ref}
  98. className={cn(
  99. "relative flex w-full 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",
  100. className,
  101. )}
  102. {...props}
  103. >
  104. <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
  105. <SelectPrimitive.ItemIndicator>
  106. <Check className="h-4 w-4" />
  107. </SelectPrimitive.ItemIndicator>
  108. </span>
  109. <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
  110. </SelectPrimitive.Item>
  111. ));
  112. SelectItem.displayName = SelectPrimitive.Item.displayName;
  113. export {
  114. Select,
  115. SelectGroup,
  116. SelectValue,
  117. SelectTrigger,
  118. SelectContent,
  119. SelectItem,
  120. SelectScrollUpButton,
  121. SelectScrollDownButton,
  122. };