UNPKG

@coreui/react-pro

Version:

UI Components Library for React.js

124 lines (103 loc) 2.85 kB
import { useEffect, useRef, useState } from 'react' import { type Options, type Placement } from '@popperjs/core' import { usePopper } from './usePopper' import { isRTL } from '../utils' export const useDropdownWithPopper = <T extends HTMLElement = never>( popperConfig?: Partial<Options>, ) => { const dropdownRefElement = useRef<T>(null) const dropdownMenuElement = useRef<HTMLDivElement | null>(null) const [isOpen, setIsOpen] = useState<boolean>(false) const { popper, initPopper, destroyPopper } = usePopper() const _popperConfig = { placement: (isRTL(dropdownRefElement.current) ? 'bottom-end' : 'bottom-start') as Placement, modifiers: [ { name: 'preventOverflow', options: { boundary: 'clippingParents', }, }, { name: 'offset', options: { offset: [0, 2], }, }, ], ...popperConfig, } const closeDropdown = () => { setIsOpen(false) } const openDropdown = () => { setIsOpen(true) } const toggleDropdown = () => { setIsOpen((prev) => !prev) } const updatePopper = () => { if (popper) { popper.update() } } const handleKeyUp = (event: KeyboardEvent) => { if (event.key === 'Escape') { setIsOpen(false) return } if (event.key === 'Tab') { if ( dropdownRefElement.current && dropdownRefElement.current.contains(document.activeElement as HTMLElement) ) { return } if ( dropdownMenuElement.current && dropdownMenuElement.current.contains(document.activeElement as HTMLElement) ) { return } setIsOpen(false) } } const handleMouseUp = (event: Event) => { if ( (dropdownMenuElement.current && dropdownMenuElement.current.contains(event.target as HTMLElement)) || (dropdownRefElement.current && dropdownRefElement.current.contains(event.target as HTMLElement)) ) { return } setIsOpen(false) } useEffect(() => { if (isOpen) { window.addEventListener('mouseup', handleMouseUp) window.addEventListener('keyup', handleKeyUp) if (dropdownRefElement.current && dropdownMenuElement.current) { initPopper(dropdownRefElement.current, dropdownMenuElement.current, _popperConfig) } } else { window.removeEventListener('mouseup', handleMouseUp) window.removeEventListener('keyup', handleKeyUp) destroyPopper() } return () => { window.removeEventListener('mouseup', handleMouseUp) window.removeEventListener('keyup', handleKeyUp) destroyPopper() } }, [isOpen]) return { dropdownMenuElement, dropdownRefElement, isOpen, closeDropdown, openDropdown, toggleDropdown, updatePopper, } }