Skip to content

Commit

Permalink
fix: Popup mouseDown inside and mouseUp outside should not close popup (
Browse files Browse the repository at this point in the history
#376)

* fix: click out side

* test: add test case
  • Loading branch information
zombieJ authored May 5, 2023
1 parent 6b889e7 commit 42dedf2
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 10 deletions.
2 changes: 1 addition & 1 deletion docs/examples/container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export default () => {
</div>
}
popupStyle={{ boxShadow: '0 0 5px red' }}
popupVisible
// popupVisible
// getPopupContainer={() => popHolderRef.current}
popupPlacement={popupPlacement}
builtinPlacements={builtinPlacements}
Expand Down
43 changes: 34 additions & 9 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,22 @@ import useWatch from './hooks/useWatch';
import type {
ActionType,
AlignType,
AnimationType,
ArrowType,
ArrowTypeOuter,
AnimationType,
BuildInPlacements,
TransitionNameType,
} from './interface';
import Popup from './Popup';
import TriggerWrapper from './TriggerWrapper';
import { getAlignPopupClassName, getMotion, getWin } from './util';

export type { BuildInPlacements, AlignType, ActionType, ArrowTypeOuter as ArrowType };
export type {
BuildInPlacements,
AlignType,
ActionType,
ArrowTypeOuter as ArrowType,
};

export interface TriggerRef {
forceAlign: VoidFunction;
Expand Down Expand Up @@ -495,8 +500,16 @@ export function generateTrigger(
// Click to hide is special action since click popup element should not hide
React.useEffect(() => {
if (clickToHide && popupEle && (!mask || maskClosable)) {
let clickInside = false;

// User may mouseDown inside and drag out of popup and mouse up
// Record here to prevent close
const onWindowMouseDown = ({ target }: MouseEvent) => {
clickInside = inPopupOrChild(target);
};

const onWindowClick = ({ target }: MouseEvent) => {
if (openRef.current && !inPopupOrChild(target)) {
if (openRef.current && !clickInside && !inPopupOrChild(target)) {
triggerOpen(false);
}
};
Expand All @@ -505,11 +518,16 @@ export function generateTrigger(

const targetRoot = targetEle?.getRootNode();

win.addEventListener('mousedown', onWindowMouseDown);
win.addEventListener('click', onWindowClick);

// shadow root
const inShadow = targetRoot && targetRoot !== targetEle.ownerDocument;
if (inShadow) {
(targetRoot as ShadowRoot).addEventListener(
'mousedown',
onWindowMouseDown,
);
(targetRoot as ShadowRoot).addEventListener('click', onWindowClick);
}

Expand All @@ -524,9 +542,14 @@ export function generateTrigger(
}

return () => {
win.removeEventListener('mousedown', onWindowMouseDown);
win.removeEventListener('click', onWindowClick);

if (inShadow) {
(targetRoot as ShadowRoot).removeEventListener(
'mousedown',
onWindowMouseDown,
);
(targetRoot as ShadowRoot).removeEventListener(
'click',
onWindowClick,
Expand Down Expand Up @@ -627,12 +650,14 @@ export function generateTrigger(
...passedProps,
});

const innerArrow: ArrowType = arrow ? {
// true and Object likely
...(arrow !== true ? arrow : {}),
x: arrowX,
y: arrowY
}: null;
const innerArrow: ArrowType = arrow
? {
// true and Object likely
...(arrow !== true ? arrow : {}),
x: arrowX,
y: arrowY,
}
: null;

// Render
return (
Expand Down
52 changes: 52 additions & 0 deletions tests/basic.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -936,4 +936,56 @@ describe('Trigger.Basic', () => {
await awaitFakeTimer();
expect(document.querySelector('.rc-trigger-popup-hidden')).toBeTruthy();
});

describe('click window to hide', () => {
it('should hide', async () => {
const onPopupVisibleChange = jest.fn();

const { container } = render(
<Trigger
onPopupVisibleChange={onPopupVisibleChange}
action="click"
popup={<strong>trigger</strong>}
>
<div className="target" />
</Trigger>,
);

fireEvent.click(container.querySelector('.target'));
await awaitFakeTimer();
expect(onPopupVisibleChange).toHaveBeenCalledWith(true);
onPopupVisibleChange.mockReset();

// Click outside to close
fireEvent.mouseDown(document.body);
fireEvent.click(document.body);
await awaitFakeTimer();
expect(onPopupVisibleChange).toHaveBeenCalledWith(false);
});

it('should not hide when mouseDown inside but mouseUp outside', async () => {
const onPopupVisibleChange = jest.fn();

const { container } = render(
<Trigger
onPopupVisibleChange={onPopupVisibleChange}
action="click"
popup={<strong>trigger</strong>}
>
<div className="target" />
</Trigger>,
);

fireEvent.click(container.querySelector('.target'));
await awaitFakeTimer();
expect(onPopupVisibleChange).toHaveBeenCalledWith(true);
onPopupVisibleChange.mockReset();

// Click outside to close
fireEvent.mouseDown(document.querySelector('strong'));
fireEvent.click(document.body);
await awaitFakeTimer();
expect(onPopupVisibleChange).not.toHaveBeenCalled();
});
});
});

0 comments on commit 42dedf2

Please sign in to comment.