Skip to content

Commit a412327

Browse files
authored
fix: Use pointerDown to check if click with portal (#493)
* fix: use pointer to handle mouseDown * test: add test case
1 parent d8bfea2 commit a412327

File tree

4 files changed

+24
-14
lines changed

4 files changed

+24
-14
lines changed

src/Popup/index.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export interface PopupProps {
2020
onMouseEnter?: React.MouseEventHandler<HTMLDivElement>;
2121
onMouseLeave?: React.MouseEventHandler<HTMLDivElement>;
2222
onPointerEnter?: React.MouseEventHandler<HTMLDivElement>;
23-
onMouseDownCapture?: React.MouseEventHandler<HTMLDivElement>;
23+
onPointerDownCapture?: React.MouseEventHandler<HTMLDivElement>;
2424
zIndex?: number;
2525

2626
mask?: boolean;
@@ -106,7 +106,7 @@ const Popup = React.forwardRef<HTMLDivElement, PopupProps>((props, ref) => {
106106
onMouseEnter,
107107
onMouseLeave,
108108
onPointerEnter,
109-
onMouseDownCapture,
109+
onPointerDownCapture,
110110

111111
ready,
112112
offsetX,
@@ -257,7 +257,7 @@ const Popup = React.forwardRef<HTMLDivElement, PopupProps>((props, ref) => {
257257
onMouseLeave={onMouseLeave}
258258
onPointerEnter={onPointerEnter}
259259
onClick={onClick}
260-
onMouseDownCapture={onMouseDownCapture}
260+
onPointerDownCapture={onPointerDownCapture}
261261
>
262262
{arrow && (
263263
<Arrow

src/hooks/useWinClick.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,28 @@ export default function useWinClick(
1616
const openRef = React.useRef(open);
1717
openRef.current = open;
1818

19+
const popupPointerDownRef = React.useRef(false);
20+
1921
// Click to hide is special action since click popup element should not hide
2022
React.useEffect(() => {
2123
if (clickToHide && popupEle && (!mask || maskClosable)) {
24+
const onPointerDown = () => {
25+
popupPointerDownRef.current = false;
26+
};
27+
2228
const onTriggerClose = (e: MouseEvent) => {
2329
if (
2430
openRef.current &&
25-
!inPopupOrChild(e.composedPath?.()?.[0] || e.target)
31+
!inPopupOrChild(e.composedPath?.()?.[0] || e.target) &&
32+
!popupPointerDownRef.current
2633
) {
2734
triggerOpen(false);
2835
}
2936
};
3037

3138
const win = getWin(popupEle);
3239

40+
win.addEventListener('pointerdown', onPointerDown, true);
3341
win.addEventListener('mousedown', onTriggerClose, true);
3442
win.addEventListener('contextmenu', onTriggerClose, true);
3543

@@ -52,6 +60,7 @@ export default function useWinClick(
5260
}
5361

5462
return () => {
63+
win.removeEventListener('pointerdown', onPointerDown, true);
5564
win.removeEventListener('mousedown', onTriggerClose, true);
5665
win.removeEventListener('contextmenu', onTriggerClose, true);
5766

@@ -70,4 +79,10 @@ export default function useWinClick(
7079
};
7180
}
7281
}, [clickToHide, targetEle, popupEle, mask, maskClosable]);
82+
83+
function onPopupPointerDown() {
84+
popupPointerDownRef.current = true;
85+
}
86+
87+
return onPopupPointerDown;
7388
}

src/index.tsx

+2-9
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ export function generateTrigger(
550550
}
551551

552552
// Click to hide is special action since click popup element should not hide
553-
useWinClick(
553+
const onPopupPointerDown = useWinClick(
554554
mergedOpen,
555555
clickToHide,
556556
targetEle,
@@ -722,14 +722,7 @@ export function generateTrigger(
722722
fresh={fresh}
723723
// Click
724724
onClick={onPopupClick}
725-
onMouseDownCapture={() => {
726-
// Additional check for click to hide
727-
// Since `createPortal` will not included in the popup element
728-
// So we use capture to handle this
729-
if (clickToHide) {
730-
triggerOpen(true);
731-
}
732-
}}
725+
onPointerDownCapture={onPopupPointerDown}
733726
// Mask
734727
mask={mask}
735728
// Motion

tests/basic.test.jsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -1220,11 +1220,13 @@ describe('Trigger.Basic', () => {
12201220
expect(isPopupHidden()).toBeFalsy();
12211221

12221222
// Click portal should not close
1223-
fireEvent.click(document.querySelector('.portal'));
1223+
fireEvent.pointerDown(document.querySelector('.portal'));
1224+
fireEvent.mouseDown(document.querySelector('.portal'));
12241225
await awaitFakeTimer();
12251226
expect(isPopupHidden()).toBeFalsy();
12261227

12271228
// Click outside to close
1229+
fireEvent.pointerDown(document.querySelector('.outer'));
12281230
fireEvent.mouseDown(container.querySelector('.outer'));
12291231
await awaitFakeTimer();
12301232
expect(isPopupHidden()).toBeTruthy();

0 commit comments

Comments
 (0)