diff --git a/src/Popup/index.tsx b/src/Popup/index.tsx index a1052ab2..47666c19 100644 --- a/src/Popup/index.tsx +++ b/src/Popup/index.tsx @@ -20,7 +20,7 @@ export interface PopupProps { onMouseEnter?: React.MouseEventHandler; onMouseLeave?: React.MouseEventHandler; onPointerEnter?: React.MouseEventHandler; - onMouseDownCapture?: React.MouseEventHandler; + onPointerDownCapture?: React.MouseEventHandler; zIndex?: number; mask?: boolean; @@ -106,7 +106,7 @@ const Popup = React.forwardRef((props, ref) => { onMouseEnter, onMouseLeave, onPointerEnter, - onMouseDownCapture, + onPointerDownCapture, ready, offsetX, @@ -257,7 +257,7 @@ const Popup = React.forwardRef((props, ref) => { onMouseLeave={onMouseLeave} onPointerEnter={onPointerEnter} onClick={onClick} - onMouseDownCapture={onMouseDownCapture} + onPointerDownCapture={onPointerDownCapture} > {arrow && ( { if (clickToHide && popupEle && (!mask || maskClosable)) { + const onPointerDown = () => { + popupPointerDownRef.current = false; + }; + const onTriggerClose = (e: MouseEvent) => { if ( openRef.current && - !inPopupOrChild(e.composedPath?.()?.[0] || e.target) + !inPopupOrChild(e.composedPath?.()?.[0] || e.target) && + !popupPointerDownRef.current ) { triggerOpen(false); } @@ -30,6 +37,7 @@ export default function useWinClick( const win = getWin(popupEle); + win.addEventListener('pointerdown', onPointerDown, true); win.addEventListener('mousedown', onTriggerClose, true); win.addEventListener('contextmenu', onTriggerClose, true); @@ -52,6 +60,7 @@ export default function useWinClick( } return () => { + win.removeEventListener('pointerdown', onPointerDown, true); win.removeEventListener('mousedown', onTriggerClose, true); win.removeEventListener('contextmenu', onTriggerClose, true); @@ -70,4 +79,10 @@ export default function useWinClick( }; } }, [clickToHide, targetEle, popupEle, mask, maskClosable]); + + function onPopupPointerDown() { + popupPointerDownRef.current = true; + } + + return onPopupPointerDown; } diff --git a/src/index.tsx b/src/index.tsx index 7a85dc9d..ac4b841e 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -550,7 +550,7 @@ export function generateTrigger( } // Click to hide is special action since click popup element should not hide - useWinClick( + const onPopupPointerDown = useWinClick( mergedOpen, clickToHide, targetEle, @@ -722,14 +722,7 @@ export function generateTrigger( fresh={fresh} // Click onClick={onPopupClick} - onMouseDownCapture={() => { - // Additional check for click to hide - // Since `createPortal` will not included in the popup element - // So we use capture to handle this - if (clickToHide) { - triggerOpen(true); - } - }} + onPointerDownCapture={onPopupPointerDown} // Mask mask={mask} // Motion diff --git a/tests/basic.test.jsx b/tests/basic.test.jsx index e5eb0aa3..071878b6 100644 --- a/tests/basic.test.jsx +++ b/tests/basic.test.jsx @@ -1220,11 +1220,13 @@ describe('Trigger.Basic', () => { expect(isPopupHidden()).toBeFalsy(); // Click portal should not close - fireEvent.click(document.querySelector('.portal')); + fireEvent.pointerDown(document.querySelector('.portal')); + fireEvent.mouseDown(document.querySelector('.portal')); await awaitFakeTimer(); expect(isPopupHidden()).toBeFalsy(); // Click outside to close + fireEvent.pointerDown(document.querySelector('.outer')); fireEvent.mouseDown(container.querySelector('.outer')); await awaitFakeTimer(); expect(isPopupHidden()).toBeTruthy();