Skip to content

Commit df5caa4

Browse files
committed
Support React 16
1 parent 402016e commit df5caa4

File tree

3 files changed

+81
-32
lines changed

3 files changed

+81
-32
lines changed

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,15 @@
4343
},
4444
"devDependencies": {
4545
"async": "~1.5.0",
46+
"core-js": "^2.5.1",
4647
"expect.js": "0.3.x",
4748
"jquery": "~1.11.3",
4849
"object-assign": "~4.0.1",
4950
"pre-commit": "1.x",
50-
"rc-tools": "6.x",
5151
"rc-test": "6.x",
52-
"react": "15.x",
53-
"react-dom": "15.x"
52+
"rc-tools": "6.x",
53+
"react": "^16.0.0-rc.3",
54+
"react-dom": "^16.0.0-rc.3"
5455
},
5556
"pre-commit": [
5657
"lint"

src/index.js

Lines changed: 75 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
3-
import { findDOMNode } from 'react-dom';
3+
import { findDOMNode, createPortal } from 'react-dom';
44
import createReactClass from 'create-react-class';
55
import contains from 'rc-util/lib/Dom/contains';
66
import addEventListener from 'rc-util/lib/Dom/addEventListener';
@@ -22,6 +22,39 @@ function returnDocument() {
2222
const ALL_HANDLERS = ['onClick', 'onMouseDown', 'onTouchStart', 'onMouseEnter',
2323
'onMouseLeave', 'onFocus', 'onBlur'];
2424

25+
const IS_REACT_16 = !!createPortal;
26+
27+
const mixins = [];
28+
29+
function getContainer(instance) {
30+
const { props } = instance;
31+
const popupContainer = document.createElement('div');
32+
// Make sure default popup container will never cause scrollbar appearing
33+
// https://github.com/react-component/trigger/issues/41
34+
popupContainer.style.position = 'absolute';
35+
popupContainer.style.top = '0';
36+
popupContainer.style.left = '0';
37+
popupContainer.style.width = '100%';
38+
const mountNode = props.getPopupContainer ?
39+
props.getPopupContainer(findDOMNode(instance)) : props.getDocument().body;
40+
mountNode.appendChild(popupContainer);
41+
return popupContainer;
42+
}
43+
44+
if (!IS_REACT_16) {
45+
mixins.push(
46+
getContainerRenderMixin({
47+
autoMount: false,
48+
49+
isVisible(instance) {
50+
return instance.state.popupVisible;
51+
},
52+
53+
getContainer,
54+
})
55+
);
56+
}
57+
2558
const Trigger = createReactClass({
2659
displayName: 'Trigger',
2760
propTypes: {
@@ -66,30 +99,7 @@ const Trigger = createReactClass({
6699
maskAnimation: PropTypes.string,
67100
},
68101

69-
mixins: [
70-
getContainerRenderMixin({
71-
autoMount: false,
72-
73-
isVisible(instance) {
74-
return instance.state.popupVisible;
75-
},
76-
77-
getContainer(instance) {
78-
const { props } = instance;
79-
const popupContainer = document.createElement('div');
80-
// Make sure default popup container will never cause scrollbar appearing
81-
// https://github.com/react-component/trigger/issues/41
82-
popupContainer.style.position = 'absolute';
83-
popupContainer.style.top = '0';
84-
popupContainer.style.left = '0';
85-
popupContainer.style.width = '100%';
86-
const mountNode = props.getPopupContainer ?
87-
props.getPopupContainer(findDOMNode(instance)) : props.getDocument().body;
88-
mountNode.appendChild(popupContainer);
89-
return popupContainer;
90-
},
91-
}),
92-
],
102+
mixins,
93103

94104
getDefaultProps() {
95105
return {
@@ -154,11 +164,16 @@ const Trigger = createReactClass({
154164
componentDidUpdate(_, prevState) {
155165
const props = this.props;
156166
const state = this.state;
157-
this.renderComponent(null, () => {
167+
const triggerAfterPopupVisibleChange = () => {
158168
if (prevState.popupVisible !== state.popupVisible) {
159169
props.afterPopupVisibleChange(state.popupVisible);
160170
}
161-
});
171+
};
172+
if (!IS_REACT_16) {
173+
this.renderComponent(null, triggerAfterPopupVisibleChange);
174+
} else {
175+
triggerAfterPopupVisibleChange();
176+
}
162177

163178
// We must listen to `mousedown` or `touchstart`, edge case:
164179
// https://github.com/ant-design/ant-design/issues/5804
@@ -186,6 +201,9 @@ const Trigger = createReactClass({
186201
componentWillUnmount() {
187202
this.clearDelayTimer();
188203
this.clearOutsideHandler();
204+
if (IS_REACT_16) {
205+
this.removeContainer();
206+
}
189207
},
190208

191209
onMouseEnter(e) {
@@ -341,6 +359,7 @@ const Trigger = createReactClass({
341359
transitionName={props.popupTransitionName}
342360
maskAnimation={props.maskAnimation}
343361
maskTransitionName={props.maskTransitionName}
362+
ref={this.savePopup}
344363
>
345364
{typeof props.popup === 'function' ? props.popup() : props.popup}
346365
</Popup>
@@ -391,6 +410,12 @@ const Trigger = createReactClass({
391410
}
392411
},
393412

413+
removeContainer() {
414+
if (this._container) {
415+
this._container.parentNode.removeChild(this._container);
416+
}
417+
},
418+
394419
createTwoChains(event) {
395420
const childPros = this.props.children.props;
396421
const props = this.props;
@@ -450,11 +475,18 @@ const Trigger = createReactClass({
450475
this.setPopupVisible(false);
451476
},
452477

478+
savePopup(node) {
479+
if (IS_REACT_16) {
480+
this._component = node;
481+
}
482+
},
483+
453484
render() {
485+
const { popupVisible } = this.state;
454486
const props = this.props;
455487
const children = props.children;
456488
const child = React.Children.only(children);
457-
const newChildProps = {};
489+
const newChildProps = { key: 'target' };
458490
if (this.isClickToHide() || this.isClickToShow()) {
459491
newChildProps.onClick = this.onClick;
460492
newChildProps.onMouseDown = this.onMouseDown;
@@ -482,7 +514,21 @@ const Trigger = createReactClass({
482514
newChildProps.onBlur = this.createTwoChains('onBlur');
483515
}
484516

485-
return React.cloneElement(child, newChildProps);
517+
if (!IS_REACT_16) {
518+
return React.cloneElement(child, newChildProps);
519+
}
520+
521+
let portal;
522+
// prevent unmounting when visible change to false
523+
if (popupVisible || this._component) {
524+
this._container = this._container || getContainer(this);
525+
portal = createPortal(this.getComponent(), this._container);
526+
}
527+
528+
return [
529+
React.cloneElement(child, newChildProps),
530+
portal,
531+
];
486532
},
487533
});
488534

tests/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
/* eslint no-console:0 */
22

3+
import 'core-js/es6/map';
4+
import 'core-js/es6/set';
35
import expect from 'expect.js';
46
import React from 'react';
57
import ReactDOM from 'react-dom';

0 commit comments

Comments
 (0)