select.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import * as React from 'react'
  2. import * as SelectPrimitive from '@radix-ui/react-select'
  3. import { Check, ChevronDown, ChevronUp } from 'lucide-react'
  4. import { cn } from '../../utils'
  5. const Select = SelectPrimitive.Root
  6. const SelectGroup = SelectPrimitive.Group
  7. const SelectValue = SelectPrimitive.Value
  8. const SelectTrigger = React.forwardRef<
  9. React.ElementRef<typeof SelectPrimitive.Trigger>,
  10. React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
  11. >(({ className, children, ...props }, ref) => (
  12. <SelectPrimitive.Trigger
  13. ref={ref}
  14. className={cn(
  15. '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 data-[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',
  16. className
  17. )}
  18. {...props}
  19. >
  20. {children}
  21. <SelectPrimitive.Icon asChild>
  22. <ChevronDown className="h-4 w-4 opacity-50" />
  23. </SelectPrimitive.Icon>
  24. </SelectPrimitive.Trigger>
  25. ))
  26. SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
  27. const SelectScrollUpButton = React.forwardRef<
  28. React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
  29. React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
  30. >(({ className, ...props }, ref) => (
  31. <SelectPrimitive.ScrollUpButton
  32. ref={ref}
  33. className={cn(
  34. 'flex cursor-default items-center justify-center py-1',
  35. className
  36. )}
  37. {...props}
  38. >
  39. <ChevronUp className="h-4 w-4" />
  40. </SelectPrimitive.ScrollUpButton>
  41. ))
  42. SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
  43. const SelectScrollDownButton = React.forwardRef<
  44. React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
  45. React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
  46. >(({ className, ...props }, ref) => (
  47. <SelectPrimitive.ScrollDownButton
  48. ref={ref}
  49. className={cn(
  50. 'flex cursor-default items-center justify-center py-1',
  51. className
  52. )}
  53. {...props}
  54. >
  55. <ChevronDown className="h-4 w-4" />
  56. </SelectPrimitive.ScrollDownButton>
  57. ))
  58. SelectScrollDownButton.displayName =
  59. SelectPrimitive.ScrollDownButton.displayName
  60. const SelectContent = React.forwardRef<
  61. React.ElementRef<typeof SelectPrimitive.Content>,
  62. React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
  63. >(({ className, children, position = 'popper', ...props }, ref) => (
  64. <SelectPrimitive.Portal>
  65. <SelectPrimitive.Content
  66. ref={ref}
  67. className={cn(
  68. 'relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-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 origin-[--radix-select-content-transform-origin]',
  69. position === 'popper' &&
  70. 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
  71. className
  72. )}
  73. position={position}
  74. {...props}
  75. >
  76. <SelectScrollUpButton />
  77. <SelectPrimitive.Viewport
  78. className={cn(
  79. 'p-1',
  80. position === 'popper' &&
  81. 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]'
  82. )}
  83. >
  84. {children}
  85. </SelectPrimitive.Viewport>
  86. <SelectScrollDownButton />
  87. </SelectPrimitive.Content>
  88. </SelectPrimitive.Portal>
  89. ))
  90. SelectContent.displayName = SelectPrimitive.Content.displayName
  91. const SelectLabel = React.forwardRef<
  92. React.ElementRef<typeof SelectPrimitive.Label>,
  93. React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
  94. >(({ className, ...props }, ref) => (
  95. <SelectPrimitive.Label
  96. ref={ref}
  97. className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', className)}
  98. {...props}
  99. />
  100. ))
  101. SelectLabel.displayName = SelectPrimitive.Label.displayName
  102. const SelectItem = React.forwardRef<
  103. React.ElementRef<typeof SelectPrimitive.Item>,
  104. React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
  105. >(({ className, children, ...props }, ref) => (
  106. <SelectPrimitive.Item
  107. ref={ref}
  108. className={cn(
  109. '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',
  110. className
  111. )}
  112. {...props}
  113. >
  114. <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
  115. <SelectPrimitive.ItemIndicator>
  116. <Check className="h-4 w-4" />
  117. </SelectPrimitive.ItemIndicator>
  118. </span>
  119. <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
  120. </SelectPrimitive.Item>
  121. ))
  122. SelectItem.displayName = SelectPrimitive.Item.displayName
  123. const SelectSeparator = React.forwardRef<
  124. React.ElementRef<typeof SelectPrimitive.Separator>,
  125. React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
  126. >(({ className, ...props }, ref) => (
  127. <SelectPrimitive.Separator
  128. ref={ref}
  129. className={cn('-mx-1 my-1 h-px bg-muted', className)}
  130. {...props}
  131. />
  132. ))
  133. SelectSeparator.displayName = SelectPrimitive.Separator.displayName
  134. export {
  135. Select,
  136. SelectGroup,
  137. SelectValue,
  138. SelectTrigger,
  139. SelectContent,
  140. SelectLabel,
  141. SelectItem,
  142. SelectSeparator,
  143. SelectScrollUpButton,
  144. SelectScrollDownButton,
  145. }