dropdown-menu.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import React, { forwardRef } from 'react'
  2. import {
  3. Dropdown as BS5Dropdown,
  4. DropdownToggle as BS5DropdownToggle,
  5. DropdownMenu as BS5DropdownMenu,
  6. DropdownItem as BS5DropdownItem,
  7. DropdownDivider as BS5DropdownDivider,
  8. DropdownHeader as BS5DropdownHeader,
  9. } from 'react-bootstrap-5'
  10. import type {
  11. DropdownProps,
  12. DropdownItemProps,
  13. DropdownToggleProps,
  14. DropdownMenuProps,
  15. DropdownDividerProps,
  16. DropdownHeaderProps,
  17. } from '@/features/ui/components/types/dropdown-menu-props'
  18. import MaterialIcon from '@/shared/components/material-icon'
  19. export function Dropdown({ ...props }: DropdownProps) {
  20. return <BS5Dropdown {...props} />
  21. }
  22. export const DropdownItem = forwardRef<
  23. typeof BS5DropdownItem,
  24. DropdownItemProps
  25. >(
  26. (
  27. { active, children, description, leadingIcon, trailingIcon, ...props },
  28. ref
  29. ) => {
  30. let leadingIconComponent = null
  31. if (leadingIcon) {
  32. if (typeof leadingIcon === 'string') {
  33. leadingIconComponent = (
  34. <MaterialIcon
  35. className="dropdown-item-leading-icon"
  36. type={leadingIcon}
  37. />
  38. )
  39. } else {
  40. leadingIconComponent = (
  41. <span className="dropdown-item-leading-icon" aria-hidden="true">
  42. {leadingIcon}
  43. </span>
  44. )
  45. }
  46. }
  47. let trailingIconComponent = null
  48. if (trailingIcon) {
  49. if (typeof trailingIcon === 'string') {
  50. const trailingIconType = active ? 'check' : trailingIcon
  51. trailingIconComponent = (
  52. <MaterialIcon
  53. className="dropdown-item-trailing-icon"
  54. type={trailingIconType}
  55. />
  56. )
  57. } else {
  58. trailingIconComponent = (
  59. <span className="dropdown-item-leading-icon" aria-hidden="true">
  60. {trailingIcon}
  61. </span>
  62. )
  63. }
  64. }
  65. return (
  66. <BS5DropdownItem
  67. active={active}
  68. className={description ? 'dropdown-item-description-container' : ''}
  69. role="menuitem"
  70. {...props}
  71. ref={ref}
  72. >
  73. {leadingIconComponent}
  74. {children}
  75. {trailingIconComponent}
  76. {description && (
  77. <span className="dropdown-item-description">{description}</span>
  78. )}
  79. </BS5DropdownItem>
  80. )
  81. }
  82. )
  83. DropdownItem.displayName = 'DropdownItem'
  84. export function DropdownToggle({ ...props }: DropdownToggleProps) {
  85. return <BS5DropdownToggle {...props} />
  86. }
  87. export function DropdownMenu({ as = 'ul', ...props }: DropdownMenuProps) {
  88. return <BS5DropdownMenu as={as} role="menu" {...props} />
  89. }
  90. export function DropdownDivider({ as = 'li' }: DropdownDividerProps) {
  91. return <BS5DropdownDivider as={as} />
  92. }
  93. export function DropdownHeader({ as = 'li', ...props }: DropdownHeaderProps) {
  94. return <BS5DropdownHeader as={as} {...props} />
  95. }