UNPKG

@nex-ui/react

Version:

🎉 A beautiful, modern, and reliable React component library.

95 lines (92 loc) • 3.46 kB
"use client"; import { ownerDocument, addEventListener, mergeProps, mergeRefs } from '@nex-ui/utils'; import { useRef, useEffect, isValidElement, cloneElement } from 'react'; import { usePopper } from './PopperContext.mjs'; import { isFocusVisible } from '../utils/isFocusVisible.mjs'; const PopperTrigger = (props)=>{ const focusVisibleRef = useRef(false); const { open, setOpen, handleClose, handleOpen, referenceRef, popperRootRef } = usePopper(); const { children, elementProps, action = 'hover', interactive = true, closeOnClick = true } = props; useEffect(()=>{ if (open && action === 'click') { const doc = ownerDocument(referenceRef.current); return addEventListener(doc.body, 'click', (e)=>{ // istanbul ignore next if (!open) return; const target = e.target; if (!interactive || !popperRootRef?.current?.contains(target) && !referenceRef?.current?.contains(target)) { handleClose(); } }); } }, [ action, handleClose, interactive, open, popperRootRef, referenceRef ]); useEffect(()=>{ if (open && interactive && action === 'hover' && popperRootRef.current) { const removeMouseenter = addEventListener(popperRootRef.current, 'mouseenter', handleOpen); const removeMouseleave = addEventListener(popperRootRef.current, 'mouseleave', handleClose); return ()=>{ removeMouseenter(); removeMouseleave(); }; } }, [ action, handleClose, interactive, open, popperRootRef, handleOpen ]); const renderChildren = ()=>{ const element = children; const props = { ref: referenceRef }; if (action === 'click') { const handleClick = ()=>{ if (!open) { handleOpen(); } else if (closeOnClick) { setOpen(false); } }; props.onClick = handleClick; } else if (action === 'hover') { const handleMouseEnter = handleOpen; const handleMouseLeave = handleClose; const handleClick = ()=>{ if (closeOnClick && open) setOpen(false); }; const handleFocus = (event)=>{ if (isFocusVisible(event.currentTarget)) { handleOpen(); focusVisibleRef.current = true; } }; const handleBlur = (event)=>{ if (focusVisibleRef.current && !isFocusVisible(event.currentTarget)) { handleClose(); focusVisibleRef.current = false; } }; props.onMouseEnter = handleMouseEnter; props.onMouseLeave = handleMouseLeave; props.onClick = handleClick; props.onFocus = handleFocus; props.onBlur = handleBlur; } return /*#__PURE__*/ cloneElement(element, { ...mergeProps(elementProps, element.props, props), ref: mergeRefs(elementProps?.ref, element.props.ref, props.ref) }); }; return /*#__PURE__*/ isValidElement(children) ? renderChildren() : children; }; export { PopperTrigger };