dropdown-menu-with-ref.tsx 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. import { forwardRef } from 'react'
  2. import classnames from 'classnames'
  3. // @ts-ignore
  4. // eslint-disable-next-line import/no-extraneous-dependencies
  5. import RootCloseWrapper from 'react-overlays/lib/RootCloseWrapper'
  6. import { DropdownProps } from 'react-bootstrap'
  7. import { MergeAndOverride } from '../../../../../types/utils'
  8. type DropdownMenuWithRefProps = MergeAndOverride<
  9. Pick<DropdownProps, 'bsClass' | 'open' | 'pullRight' | 'onClose'>,
  10. {
  11. children: React.ReactNode
  12. bsRole: 'menu'
  13. menuRef: React.MutableRefObject<HTMLElement | undefined>
  14. className?: string
  15. // The props below are passed by react-bootstrap
  16. labelledBy?: string | undefined
  17. rootCloseEvent?: 'click' | 'mousedown' | undefined
  18. }
  19. >
  20. const DropdownMenuWithRef = forwardRef<
  21. HTMLUListElement,
  22. DropdownMenuWithRefProps
  23. >(function (props, ref) {
  24. const {
  25. children,
  26. bsRole,
  27. bsClass,
  28. className,
  29. open,
  30. pullRight,
  31. labelledBy,
  32. menuRef,
  33. onClose,
  34. rootCloseEvent,
  35. ...rest
  36. } = props
  37. // expose the menu reference to both the `menuRef` and `ref callback` from react-bootstrap
  38. const handleRefs = (node: HTMLUListElement) => {
  39. if (typeof ref === 'function') {
  40. ref(node)
  41. }
  42. menuRef.current = node
  43. }
  44. // Implementation as suggested in
  45. // https://react-bootstrap-v3.netlify.app/components/dropdowns/#btn-dropdowns-props-dropdown
  46. return (
  47. <RootCloseWrapper
  48. disabled={!open}
  49. onRootClose={onClose}
  50. event={rootCloseEvent}
  51. >
  52. <ul
  53. role={bsRole}
  54. className={classnames(className, bsClass, {
  55. 'dropdown-menu-right': pullRight,
  56. })}
  57. aria-labelledby={labelledBy}
  58. ref={handleRefs}
  59. {...rest}
  60. >
  61. {children}
  62. </ul>
  63. </RootCloseWrapper>
  64. )
  65. })
  66. DropdownMenuWithRef.displayName = 'DropdownMenuWithRef'
  67. export default DropdownMenuWithRef