index.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import type { FC } from 'react'
  2. import { useState } from 'react'
  3. import { DotsHorizontal } from '@/app/components/base/icons/src/vender/line/general'
  4. import {
  5. PortalToFollowElem,
  6. PortalToFollowElemContent,
  7. PortalToFollowElemTrigger,
  8. } from '@/app/components/base/portal-to-follow-elem'
  9. export type Item = {
  10. value: string | number
  11. text: string | JSX.Element
  12. }
  13. type DropdownProps = {
  14. items: Item[]
  15. secondItems?: Item[]
  16. onSelect: (item: Item) => void
  17. renderTrigger?: (open: boolean) => React.ReactNode
  18. popupClassName?: string
  19. }
  20. const Dropdown: FC<DropdownProps> = ({
  21. items,
  22. onSelect,
  23. secondItems,
  24. renderTrigger,
  25. popupClassName,
  26. }) => {
  27. const [open, setOpen] = useState(false)
  28. const handleSelect = (item: Item) => {
  29. setOpen(false)
  30. onSelect(item)
  31. }
  32. return (
  33. <PortalToFollowElem
  34. open={open}
  35. onOpenChange={setOpen}
  36. placement='bottom-end'
  37. >
  38. <PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
  39. {
  40. renderTrigger
  41. ? renderTrigger(open)
  42. : (
  43. <div
  44. className={`
  45. flex items-center justify-center w-6 h-6 cursor-pointer rounded-md
  46. ${open && 'bg-black/5'}
  47. `}
  48. >
  49. <DotsHorizontal className='w-4 h-4 text-gray-500' />
  50. </div>
  51. )
  52. }
  53. </PortalToFollowElemTrigger>
  54. <PortalToFollowElemContent className={popupClassName}>
  55. <div className='rounded-lg border-[0.5px] border-gray-200 bg-white shadow-lg text-sm text-gray-700'>
  56. {
  57. !!items.length && (
  58. <div className='p-1'>
  59. {
  60. items.map(item => (
  61. <div
  62. key={item.value}
  63. className='flex items-center px-3 h-8 rounded-lg cursor-pointer hover:bg-gray-100'
  64. onClick={() => handleSelect(item)}
  65. >
  66. {item.text}
  67. </div>
  68. ))
  69. }
  70. </div>
  71. )
  72. }
  73. {
  74. (!!items.length && !!secondItems?.length) && (
  75. <div className='h-[1px] bg-gray-100' />
  76. )
  77. }
  78. {
  79. !!secondItems?.length && (
  80. <div className='p-1'>
  81. {
  82. secondItems.map(item => (
  83. <div
  84. key={item.value}
  85. className='flex items-center px-3 h-8 rounded-lg cursor-pointer hover:bg-gray-100'
  86. onClick={() => handleSelect(item)}
  87. >
  88. {item.text}
  89. </div>
  90. ))
  91. }
  92. </div>
  93. )
  94. }
  95. </div>
  96. </PortalToFollowElemContent>
  97. </PortalToFollowElem>
  98. )
  99. }
  100. export default Dropdown