dropdown-menu-with-ref.tsx 1.8 KB

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