Skip to content

Commit ec368f0

Browse files
committed
[added] Fade Component, replaces FadeMixin
1 parent 0503507 commit ec368f0

File tree

11 files changed

+358
-79
lines changed

11 files changed

+358
-79
lines changed

docs/examples/Fade.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
2+
class Example extends React.Component {
3+
4+
constructor(...args){
5+
super(...args);
6+
this.state = {};
7+
}
8+
9+
render(){
10+
11+
return (
12+
<div>
13+
<Button onClick={()=> this.setState({ open: !this.state.open })}>
14+
click
15+
</Button>
16+
<Fade in={this.state.open}>
17+
<div>
18+
<Well>
19+
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid.
20+
Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident.
21+
</Well>
22+
</div>
23+
</Fade>
24+
</div>
25+
);
26+
}
27+
}
28+
29+
React.render(<Example/>, mountNode);

src/Fade.js

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
'use strict';
2+
import React from 'react';
3+
import Transition from './Transition';
4+
5+
class Fade extends React.Component {
6+
7+
constructor(props, context){
8+
super(props, context);
9+
}
10+
11+
render() {
12+
return (
13+
<Transition
14+
{...this.props}
15+
in={this.props.in}
16+
className='fade'
17+
enteredClassName='in'
18+
enteringClassName='in'
19+
>
20+
{ this.props.children }
21+
</Transition>
22+
);
23+
}
24+
}
25+
26+
Fade.propTypes = {
27+
/**
28+
* Fade the Component in or out.
29+
*/
30+
in: React.PropTypes.bool,
31+
32+
/**
33+
* Provide the durration of the animation in milliseconds, used to ensure that finishing callbacks are fired even if the
34+
* original browser transition end events are canceled.
35+
*/
36+
duration: React.PropTypes.number,
37+
38+
/**
39+
* A Callback fired before the component starts to fade in.
40+
*/
41+
onEnter: React.PropTypes.func,
42+
43+
/**
44+
* A Callback fired immediately after the component has started to faded in.
45+
*/
46+
onEntering: React.PropTypes.func,
47+
48+
/**
49+
* A Callback fired after the component has faded in.
50+
*/
51+
onEntered: React.PropTypes.func,
52+
53+
/**
54+
* A Callback fired before the component starts to fade out.
55+
*/
56+
onExit: React.PropTypes.func,
57+
58+
/**
59+
* A Callback fired immediately after the component has started to faded out.
60+
*/
61+
onExiting: React.PropTypes.func,
62+
63+
/**
64+
* A Callback fired after the component has faded out.
65+
*/
66+
onExited: React.PropTypes.func,
67+
68+
69+
/**
70+
* Specify whether the transitioning component should be unmounted (removed from the DOM) once the exit animation finishes.
71+
*/
72+
unmountOnExit: React.PropTypes.bool,
73+
74+
/**
75+
* Specify whether the component should fade in or out when it mounts.
76+
*/
77+
transitionAppear: React.PropTypes.bool
78+
79+
};
80+
81+
Fade.defaultProps = {
82+
in: false,
83+
duration: 300,
84+
dimension: 'height',
85+
transitionAppear: false,
86+
unmountOnExit: false
87+
};
88+
89+
export default Fade;
90+

src/Modal.js

+51-16
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import React, { cloneElement } from 'react';
44
import classNames from 'classnames';
55
import createChainedFunction from './utils/createChainedFunction';
66
import BootstrapMixin from './BootstrapMixin';
7-
import FadeMixin from './FadeMixin';
87
import domUtils from './utils/domUtils';
98
import EventListener from './utils/EventListener';
109

1110
import Portal from './Portal';
11+
import Fade from './Fade';
1212

1313
import Body from './ModalBody';
1414
import Header from './ModalHeader';
@@ -90,12 +90,17 @@ function getScrollbarSize(){
9090
document.body.removeChild(scrollDiv);
9191

9292
scrollDiv = null;
93+
return scrollbarSize;
9394
}
9495

9596

9697
const ModalMarkup = React.createClass({
9798

99+
<<<<<<< HEAD
98100
mixins: [ BootstrapMixin, FadeMixin ],
101+
=======
102+
mixins: [ BootstrapMixin ],
103+
>>>>>>> [added] Fade Component, replaces FadeMixin
99104

100105
propTypes: {
101106

@@ -166,8 +171,7 @@ const ModalMarkup = React.createClass({
166171

167172
let classes = {
168173
modal: true,
169-
fade: this.props.animation,
170-
'in': !this.props.animation
174+
in: this.props.show && !this.props.animation
171175
};
172176

173177
let modal = (
@@ -206,18 +210,22 @@ const ModalMarkup = React.createClass({
206210
},
207211

208212
renderBackdrop(modal) {
209-
let classes = {
210-
'modal-backdrop': true,
211-
fade: this.props.animation,
212-
'in': !this.props.animation
213-
};
214-
215-
let onClick = this.props.backdrop === true ?
216-
this.handleBackdropClick : null;
213+
let { animation } = this.props;
214+
let duration = Modal.BACKDROP_TRANSITION_DURATION; //eslint-disable-line no-use-before-define
215+
216+
let backdrop = (
217+
<div ref="backdrop"
218+
className={classNames('modal-backdrop', { in: this.props.show && !animation })}
219+
onClick={this.handleBackdropClick}
220+
/>
221+
);
217222

218223
return (
219224
<div>
220-
<div className={classNames(classes)} ref="backdrop" onClick={onClick} />
225+
{ animation
226+
? <Fade transitionAppear in={this.props.show} duration={duration}>{backdrop}</Fade>
227+
: backdrop
228+
}
221229
{modal}
222230
</div>
223231
);
@@ -381,16 +389,40 @@ const Modal = React.createClass({
381389
...ModalMarkup.propTypes
382390
},
383391

392+
getDefaultProps(){
393+
return {
394+
show: false,
395+
animation: true
396+
};
397+
},
398+
384399
render() {
385-
let { show, ...props } = this.props;
400+
let { children, ...props } = this.props;
401+
402+
let show = !!props.show;
386403

387404
let modal = (
388-
<ModalMarkup {...props} ref='modal'>{this.props.children}</ModalMarkup>
405+
<ModalMarkup {...props} ref='modal'>
406+
{ children }
407+
</ModalMarkup>
389408
);
390409

391410
return (
392-
<Portal container={props.container} >
393-
{ show && modal }
411+
<Portal container={props.container}>
412+
{ props.animation
413+
? (
414+
<Fade
415+
in={show}
416+
transitionAppear={show}
417+
duration={Modal.TRANSITION_DURATION}
418+
unmountOnExit
419+
>
420+
{ modal }
421+
</Fade>
422+
)
423+
: show && modal
424+
}
425+
394426
</Portal>
395427
);
396428
}
@@ -401,4 +433,7 @@ Modal.Header = Header;
401433
Modal.Title = Title;
402434
Modal.Footer = Footer;
403435

436+
Modal.TRANSITION_DURATION = 300;
437+
Modal.BACKDROP_TRANSITION_DURATION = 150;
438+
404439
export default Modal;

src/Overlay.js

+71-16
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
/*eslint-disable object-shorthand, react/prop-types */
2-
import React from 'react';
2+
import React, { cloneElement } from 'react';
33
import Portal from './Portal';
44
import Position from './Position';
55
import RootCloseWrapper from './RootCloseWrapper';
6+
import CustomPropTypes from './utils/CustomPropTypes';
7+
import Fade from './Fade';
8+
import classNames from 'classnames';
9+
610

711
class Overlay extends React.Component {
812

913
constructor(props, context){
1014
super(props, context);
15+
16+
this.state = { exited: false };
17+
this.onHiddenListener = this.handleHidden.bind(this);
18+
}
19+
20+
componentWillReceiveProps(nextProps) {
21+
if (this.props.show){
22+
this.setState({ exited: false });
23+
}
1124
}
1225

1326
render(){
@@ -17,30 +30,60 @@ class Overlay extends React.Component {
1730
, target
1831
, placement
1932
, rootClose
33+
, children
34+
, animation: Transition
2035
, ...props } = this.props;
2136

22-
let positionedChild = (
23-
<Position {...{ container, containerPadding, target, placement }}>
24-
{ this.props.children }
25-
</Position>
26-
);
37+
let child = null;
2738

28-
if (rootClose) {
29-
positionedChild = (
30-
<RootCloseWrapper onRootClose={this.props.onHide}>
31-
{ positionedChild }
32-
</RootCloseWrapper>
39+
if ( Transition === true ){
40+
Transition = Fade;
41+
}
42+
43+
if (props.show || (Transition && !this.state.exited)) {
44+
45+
child = children;
46+
47+
// Position the child before the animation to avoid `null` DOM nodes
48+
child = (
49+
<Position {...{ container, containerPadding, target, placement }}>
50+
{ child }
51+
</Position>
3352
);
53+
54+
child = Transition
55+
? (
56+
<Transition
57+
unmountOnExit
58+
in={props.show}
59+
transitionAppear={props.show}
60+
onHidden={this.onHiddenListener}
61+
>
62+
{ child }
63+
</Transition>
64+
)
65+
: cloneElement(child, { className: classNames('in', child.className) });
66+
67+
68+
if (rootClose) {
69+
child = (
70+
<RootCloseWrapper onRootClose={props.onHide}>
71+
{ child }
72+
</RootCloseWrapper>
73+
);
74+
}
3475
}
3576

3677
return (
37-
<Portal container={container} rootClose={rootClose} onRootClose={this.props.onHide}>
38-
{ props.show &&
39-
positionedChild
40-
}
78+
<Portal container={container}>
79+
{ child }
4180
</Portal>
4281
);
4382
}
83+
84+
handleHidden(){
85+
this.setState({ exited: true });
86+
}
4487
}
4588

4689
Overlay.propTypes = {
@@ -57,7 +100,19 @@ Overlay.propTypes = {
57100
/**
58101
* A Callback fired by the Overlay when it wishes to be hidden.
59102
*/
60-
onHide: React.PropTypes.func
103+
onHide: React.PropTypes.func,
104+
105+
/**
106+
* Use animation
107+
*/
108+
animation: React.PropTypes.oneOfType([
109+
React.PropTypes.bool,
110+
CustomPropTypes.elementType
111+
])
112+
};
113+
114+
Overlay.defaultProps = {
115+
animation: Fade
61116
};
62117

63118
export default Overlay;

0 commit comments

Comments
 (0)