Skip to content

Commit

Permalink
fix:Support prevent close event children stopPropagation (#251)
Browse files Browse the repository at this point in the history
* docs: Add external example

* capture it

* test: update test case
  • Loading branch information
zombieJ authored Apr 14, 2021
1 parent aca98d8 commit c15aa2d
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 133 deletions.
135 changes: 83 additions & 52 deletions examples/nested.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint no-console:0 */

import React from 'react';
import ReactDOM from 'react-dom';
import Trigger from '../src';
import '../assets/index.less';

Expand Down Expand Up @@ -36,66 +37,96 @@ const popupBorderStyle = {
padding: 10,
};

class Test extends React.Component {
saveContainerRef = (node) => {
this.containerInstanceNode = node;
};
const OuterContent = ({ getContainer }) => {
return ReactDOM.createPortal(
<div>
I am outer content
<button
onMouseDown={(e) => {
e.stopPropagation();
}}
>
Stop Pop
</button>
</div>,
getContainer(),
);
};

const Test = () => {
const containerRef = React.useRef();
const outerDivRef = React.useRef();

render() {
const innerTrigger = (
<div style={popupBorderStyle}>
<div ref={this.saveContainerRef} />
const innerTrigger = (
<div style={popupBorderStyle}>
<div ref={containerRef} />
<Trigger
popupPlacement="bottom"
action={['click']}
builtinPlacements={builtinPlacements}
getPopupContainer={() => containerRef.current}
popup={<div style={popupBorderStyle}>I am inner Trigger Popup</div>}
>
<span href="#" style={{ margin: 20 }}>
clickToShowInnerTrigger
</span>
</Trigger>
</div>
);
return (
<div style={{ margin: 200 }}>
<div>
<Trigger
popupPlacement="bottom"
popupPlacement="left"
action={['click']}
builtinPlacements={builtinPlacements}
getPopupContainer={() => this.containerInstanceNode}
popup={<div style={popupBorderStyle}>I am inner Trigger Popup</div>}
popup={
<div style={popupBorderStyle}>
i am a click popup
<OuterContent getContainer={() => outerDivRef.current} />
</div>
}
>
<span href="#" style={{ margin: 20 }}>
clickToShowInnerTrigger
<span>
<Trigger
popupPlacement="bottom"
action={['hover']}
builtinPlacements={builtinPlacements}
popup={<div style={popupBorderStyle}>i am a hover popup</div>}
>
<span href="#" style={{ margin: 20 }}>
trigger
</span>
</Trigger>
</span>
</Trigger>
</div>
);
return (
<div style={{ margin: 200 }}>
<div>
<Trigger
popupPlacement="left"
action={['click']}
builtinPlacements={builtinPlacements}
popup={<div style={popupBorderStyle}>i am a click popup</div>}
>
<span>
<Trigger
popupPlacement="bottom"
action={['hover']}
builtinPlacements={builtinPlacements}
popup={<div style={popupBorderStyle}>i am a hover popup</div>}
>
<span href="#" style={{ margin: 20 }}>
trigger
</span>
</Trigger>
</span>
</Trigger>
</div>
<div style={{ margin: 50 }}>
<Trigger
popupPlacement="right"
action={['hover']}
builtinPlacements={builtinPlacements}
popup={innerTrigger}
>
<span href="#" style={{ margin: 20 }}>
trigger
</span>
</Trigger>
</div>
<div style={{ margin: 50 }}>
<Trigger
popupPlacement="right"
action={['hover']}
builtinPlacements={builtinPlacements}
popup={innerTrigger}
>
<span href="#" style={{ margin: 20 }}>
trigger
</span>
</Trigger>
</div>
);
}
}

<div
ref={outerDivRef}
style={{
position: 'fixed',
right: 0,
bottom: 0,
width: 200,
height: 200,
background: 'red',
}}
/>
</div>
);
};

export default Test;
4 changes: 2 additions & 2 deletions src/Popup/PopupInner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,8 @@ const PopupInner = React.forwardRef<PopupInnerRef, PopupInnerProps>(
className={mergedClassName}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
onMouseDown={onMouseDown}
onTouchStart={onTouchStart}
onMouseDownCapture={onMouseDown}
onTouchStartCapture={onTouchStart}
style={{
...motionStyle,
...mergedStyle,
Expand Down
145 changes: 71 additions & 74 deletions tests/basic.test.jsx
Original file line number Diff line number Diff line change
@@ -1,67 +1,13 @@
/* eslint-disable max-classes-per-file */

import React from 'react';
import ReactDOM from 'react-dom';
import { mount } from 'enzyme';
import { act } from 'react-dom/test-utils';
import { spyElementPrototypes } from 'rc-util/lib/test/domHook';
import Portal from 'rc-util/lib/Portal';
import Trigger from '../src';

const autoAdjustOverflow = {
adjustX: 1,
adjustY: 1,
};

const targetOffsetG = [0, 0];

export const placementAlignMap = {
left: {
points: ['cr', 'cl'],
overflow: autoAdjustOverflow,
offset: [-3, 0],
targetOffsetG,
},
right: {
points: ['cl', 'cr'],
overflow: autoAdjustOverflow,
offset: [3, 0],
targetOffsetG,
},
top: {
points: ['bc', 'tc'],
overflow: autoAdjustOverflow,
offset: [0, -3],
targetOffsetG,
},
bottom: {
points: ['tc', 'bc'],
overflow: autoAdjustOverflow,
offset: [0, 3],
targetOffsetG,
},
topLeft: {
points: ['bl', 'tl'],
overflow: autoAdjustOverflow,
offset: [0, -3],
targetOffsetG,
},
topRight: {
points: ['br', 'tr'],
overflow: autoAdjustOverflow,
offset: [0, -3],
targetOffsetG,
},
bottomRight: {
points: ['tr', 'br'],
overflow: autoAdjustOverflow,
offset: [0, 3],
targetOffsetG,
},
bottomLeft: {
points: ['tl', 'bl'],
overflow: autoAdjustOverflow,
offset: [0, 3],
targetOffsetG,
},
};
import { placementAlignMap } from './util';

describe('Trigger.Basic', () => {
beforeEach(() => {
Expand Down Expand Up @@ -147,12 +93,7 @@ describe('Trigger.Basic', () => {
);

wrapper.trigger();
expect(
wrapper
.find('Popup')
.find('.x-content')
.text(),
).toBe('tooltip2');
expect(wrapper.find('Popup').find('.x-content').text()).toBe('tooltip2');

wrapper.trigger();
expect(wrapper.isHidden()).toBeTruthy();
Expand All @@ -173,12 +114,7 @@ describe('Trigger.Basic', () => {
);

wrapper.trigger();
expect(
wrapper
.find('Popup')
.find('.x-content')
.text(),
).toBe('tooltip3');
expect(wrapper.find('Popup').find('.x-content').text()).toBe('tooltip3');

wrapper.trigger();
expect(wrapper.isHidden()).toBeTruthy();
Expand Down Expand Up @@ -509,7 +445,7 @@ describe('Trigger.Basic', () => {
});

describe('stretch', () => {
const createTrigger = stretch =>
const createTrigger = (stretch) =>
mount(
<Trigger
action={['click']}
Expand Down Expand Up @@ -542,7 +478,7 @@ describe('Trigger.Basic', () => {
domSpy.mockRestore();
});

['width', 'height', 'minWidth', 'minHeight'].forEach(prop => {
['width', 'height', 'minWidth', 'minHeight'].forEach((prop) => {
it(prop, () => {
const wrapper = createTrigger(prop);

Expand Down Expand Up @@ -643,7 +579,7 @@ describe('Trigger.Basic', () => {
<div>
<button
type="button"
onMouseDown={e => {
onMouseDown={(e) => {
e.preventDefault();
e.stopPropagation();
}}
Expand Down Expand Up @@ -687,7 +623,7 @@ describe('Trigger.Basic', () => {

describe('getContainer', () => {
it('not trigger when dom not ready', () => {
const getPopupContainer = jest.fn(node => node.parentElement);
const getPopupContainer = jest.fn((node) => node.parentElement);

function Demo() {
return (
Expand Down Expand Up @@ -740,4 +676,65 @@ describe('Trigger.Basic', () => {
wrapper.unmount();
});
});

// https://github.com/ant-design/ant-design/issues/30116
it('createPortal should also work with stopPropagation', () => {
const root = document.createElement('div');
document.body.appendChild(root);

const div = document.createElement('div');
document.body.appendChild(div);

const OuterContent = ({ container }) => {
return ReactDOM.createPortal(
<button
onMouseDown={(e) => {
e.stopPropagation();
}}
>
Stop Pop
</button>,
container,
);
};

const Demo = () => {
return (
<Trigger
action={['click']}
popup={
<strong className="x-content">
tooltip2
<OuterContent container={div} />
</strong>
}
>
<div className="target">click</div>
</Trigger>
);
};

const wrapper = mount(<Demo />, { attachTo: root });

wrapper.find('.target').simulate('click');
expect(wrapper.isHidden()).toBeFalsy();

// Click should not close
wrapper.find('button').simulate('mouseDown');

// Mock document mouse click event
act(() => {
const mouseEvent = new MouseEvent('mousedown');
document.dispatchEvent(mouseEvent);
wrapper.update();
});

wrapper.update();
expect(wrapper.isHidden()).toBeFalsy();

wrapper.unmount();

document.body.removeChild(div);
document.body.removeChild(root);
});
});
2 changes: 1 addition & 1 deletion tests/mask.test.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { mount } from 'enzyme';
import Trigger from '../src';
import { placementAlignMap } from './basic.test';
import { placementAlignMap } from './util';

describe('Trigger.Mask', () => {
beforeEach(() => {
Expand Down
7 changes: 4 additions & 3 deletions tests/mobile.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import React from 'react';
import { act } from 'react-dom/test-utils';
import isMobile from 'rc-util/lib/isMobile';
import { mount } from 'enzyme';
import Trigger, { TriggerProps } from '../src';
import { placementAlignMap } from './basic.test';
import type { TriggerProps } from '../src';
import Trigger from '../src';
import { placementAlignMap } from './util';

jest.mock('rc-util/lib/isMobile');

Expand Down Expand Up @@ -53,7 +54,7 @@ describe('Trigger.Mobile', () => {
const wrapper = mount(
getTrigger({
mobile: {
popupRender: node => (
popupRender: (node) => (
<>
<div>Light</div>
{node}
Expand Down
Loading

0 comments on commit c15aa2d

Please sign in to comment.