index.tsx 2.7 KB

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