@nex-ui/react
Version:
🎉 A beautiful, modern, and reliable React component library.
95 lines (92 loc) • 3.46 kB
JavaScript
"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 };