1
1
import React from 'react' ;
2
2
import PropTypes from 'prop-types' ;
3
- import { findDOMNode } from 'react-dom' ;
3
+ import { findDOMNode , createPortal } from 'react-dom' ;
4
4
import createReactClass from 'create-react-class' ;
5
5
import contains from 'rc-util/lib/Dom/contains' ;
6
6
import addEventListener from 'rc-util/lib/Dom/addEventListener' ;
@@ -22,6 +22,39 @@ function returnDocument() {
22
22
const ALL_HANDLERS = [ 'onClick' , 'onMouseDown' , 'onTouchStart' , 'onMouseEnter' ,
23
23
'onMouseLeave' , 'onFocus' , 'onBlur' ] ;
24
24
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
+
25
58
const Trigger = createReactClass ( {
26
59
displayName : 'Trigger' ,
27
60
propTypes : {
@@ -66,30 +99,7 @@ const Trigger = createReactClass({
66
99
maskAnimation : PropTypes . string ,
67
100
} ,
68
101
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,
93
103
94
104
getDefaultProps ( ) {
95
105
return {
@@ -154,11 +164,16 @@ const Trigger = createReactClass({
154
164
componentDidUpdate ( _ , prevState ) {
155
165
const props = this . props ;
156
166
const state = this . state ;
157
- this . renderComponent ( null , ( ) => {
167
+ const triggerAfterPopupVisibleChange = ( ) => {
158
168
if ( prevState . popupVisible !== state . popupVisible ) {
159
169
props . afterPopupVisibleChange ( state . popupVisible ) ;
160
170
}
161
- } ) ;
171
+ } ;
172
+ if ( ! IS_REACT_16 ) {
173
+ this . renderComponent ( null , triggerAfterPopupVisibleChange ) ;
174
+ } else {
175
+ triggerAfterPopupVisibleChange ( ) ;
176
+ }
162
177
163
178
// We must listen to `mousedown` or `touchstart`, edge case:
164
179
// https://github.com/ant-design/ant-design/issues/5804
@@ -186,6 +201,9 @@ const Trigger = createReactClass({
186
201
componentWillUnmount ( ) {
187
202
this . clearDelayTimer ( ) ;
188
203
this . clearOutsideHandler ( ) ;
204
+ if ( IS_REACT_16 ) {
205
+ this . removeContainer ( ) ;
206
+ }
189
207
} ,
190
208
191
209
onMouseEnter ( e ) {
@@ -341,6 +359,7 @@ const Trigger = createReactClass({
341
359
transitionName = { props . popupTransitionName }
342
360
maskAnimation = { props . maskAnimation }
343
361
maskTransitionName = { props . maskTransitionName }
362
+ ref = { this . savePopup }
344
363
>
345
364
{ typeof props . popup === 'function' ? props . popup ( ) : props . popup }
346
365
</ Popup >
@@ -391,6 +410,12 @@ const Trigger = createReactClass({
391
410
}
392
411
} ,
393
412
413
+ removeContainer ( ) {
414
+ if ( this . _container ) {
415
+ this . _container . parentNode . removeChild ( this . _container ) ;
416
+ }
417
+ } ,
418
+
394
419
createTwoChains ( event ) {
395
420
const childPros = this . props . children . props ;
396
421
const props = this . props ;
@@ -450,11 +475,18 @@ const Trigger = createReactClass({
450
475
this . setPopupVisible ( false ) ;
451
476
} ,
452
477
478
+ savePopup ( node ) {
479
+ if ( IS_REACT_16 ) {
480
+ this . _component = node ;
481
+ }
482
+ } ,
483
+
453
484
render ( ) {
485
+ const { popupVisible } = this . state ;
454
486
const props = this . props ;
455
487
const children = props . children ;
456
488
const child = React . Children . only ( children ) ;
457
- const newChildProps = { } ;
489
+ const newChildProps = { key : 'target' } ;
458
490
if ( this . isClickToHide ( ) || this . isClickToShow ( ) ) {
459
491
newChildProps . onClick = this . onClick ;
460
492
newChildProps . onMouseDown = this . onMouseDown ;
@@ -482,7 +514,21 @@ const Trigger = createReactClass({
482
514
newChildProps . onBlur = this . createTwoChains ( 'onBlur' ) ;
483
515
}
484
516
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
+ ] ;
486
532
} ,
487
533
} ) ;
488
534
0 commit comments