11const React = require ( 'react' ) ;
2- const ReactDOM = require ( 'react-dom' ) ;
3- const CssEvent = require ( './utils/css-event' ) ;
42const StylePropable = require ( './mixins/style-propable' ) ;
53const Transitions = require ( './styles/transitions' ) ;
64const ClickAwayable = require ( './mixins/click-awayable' ) ;
75const FlatButton = require ( './flat-button' ) ;
86const DefaultRawTheme = require ( './styles/raw-themes/light-raw-theme' ) ;
97const ThemeManager = require ( './styles/theme-manager' ) ;
8+ const ContextPure = require ( './mixins/context-pure' ) ;
9+ const StyleResizable = require ( './mixins/style-resizable' ) ;
1010
1111const Snackbar = React . createClass ( {
1212
13- mixins : [ StylePropable , ClickAwayable ] ,
13+ mixins : [
14+ StylePropable ,
15+ StyleResizable ,
16+ ClickAwayable ,
17+ ContextPure ,
18+ ] ,
1419
1520 manuallyBindClickAway : true ,
1621
1722 // ID of the active timer.
1823 _autoHideTimerId : undefined ,
1924
25+ _oneAtTheTimeTimerId : undefined ,
26+
2027 contextTypes : {
2128 muiTheme : React . PropTypes . object ,
2229 } ,
2330
31+ getDefaultProps : function ( ) {
32+ return {
33+ openOnMount : false ,
34+ } ;
35+ } ,
36+
37+ statics : {
38+ getRelevantContextKeys ( muiTheme ) {
39+ const theme = muiTheme . snackbar ;
40+ const spacing = muiTheme . rawTheme . spacing ;
41+
42+ return {
43+ textColor : theme . textColor ,
44+ backgroundColor : theme . backgroundColor ,
45+ desktopGutter : spacing . desktopGutter ,
46+ desktopSubheaderHeight : spacing . desktopSubheaderHeight ,
47+ actionColor : theme . actionColor ,
48+ } ;
49+ } ,
50+ getChildrenClasses ( ) {
51+ return [
52+ FlatButton ,
53+ ] ;
54+ } ,
55+ } ,
56+
2457 propTypes : {
25- message : React . PropTypes . string . isRequired ,
58+ message : React . PropTypes . node . isRequired ,
2659 action : React . PropTypes . string ,
2760 autoHideDuration : React . PropTypes . number ,
2861 onActionTouchTap : React . PropTypes . func ,
@@ -44,16 +77,40 @@ const Snackbar = React.createClass({
4477
4578 getInitialState ( ) {
4679 return {
47- open : this . props . openOnMount || false ,
80+ open : this . props . openOnMount ,
81+ message : this . props . message ,
82+ action : this . props . action ,
4883 muiTheme : this . context . muiTheme ? this . context . muiTheme : ThemeManager . getMuiTheme ( DefaultRawTheme ) ,
4984 } ;
5085 } ,
5186
52- //to update theme inside state whenever a new theme is passed down
53- //from the parent / owner using context
54- componentWillReceiveProps ( nextProps , nextContext ) {
87+ componentWillReceiveProps ( nextProps , nextContext ) {
88+ //to update theme inside state whenever a new theme is passed down
89+ //from the parent / owner using context
5590 let newMuiTheme = nextContext . muiTheme ? nextContext . muiTheme : this . state . muiTheme ;
5691 this . setState ( { muiTheme : newMuiTheme } ) ;
92+
93+ if ( this . state . open ) {
94+ this . setState ( {
95+ open : false ,
96+ } ) ;
97+
98+ clearTimeout ( this . _oneAtTheTimeTimerId ) ;
99+ this . _oneAtTheTimeTimerId = setTimeout ( ( ) => {
100+ if ( this . isMounted ( ) ) {
101+ this . setState ( {
102+ message : nextProps . message ,
103+ action : nextProps . action ,
104+ open : true ,
105+ } ) ;
106+ }
107+ } , 400 ) ;
108+ } else {
109+ this . setState ( {
110+ message : nextProps . message ,
111+ action : nextProps . action ,
112+ } ) ;
113+ }
57114 } ,
58115
59116 componentDidMount ( ) {
@@ -73,86 +130,103 @@ const Snackbar = React.createClass({
73130 this . _setAutoHideTimer ( ) ;
74131
75132 //Only Bind clickaway after transition finishes
76- CssEvent . onTransitionEnd ( ReactDOM . findDOMNode ( this ) , ( ) => {
77- this . _bindClickAway ( ) ;
78- } ) ;
79- }
80- else {
133+ setTimeout ( ( ) => {
134+ if ( this . isMounted ( ) ) {
135+ this . _bindClickAway ( ) ;
136+ }
137+ } , 400 ) ;
138+ } else {
139+ clearTimeout ( this . _autoHideTimerId ) ;
81140 this . _unbindClickAway ( ) ;
82141 }
83142 }
84143 } ,
85144
86145 componentWillUnmount ( ) {
87- this . _clearAutoHideTimer ( ) ;
146+ clearTimeout ( this . _autoHideTimerId ) ;
88147 this . _unbindClickAway ( ) ;
89148 } ,
90149
91- getTheme ( ) {
92- return this . state . muiTheme . snackbar ;
93- } ,
150+ getStyles ( ) {
151+ const {
152+ textColor,
153+ backgroundColor,
154+ desktopGutter,
155+ desktopSubheaderHeight,
156+ actionColor,
157+ } = this . constructor . getRelevantContextKeys ( this . state . muiTheme ) ;
94158
95- getSpacing ( ) {
96- return this . state . muiTheme . rawTheme . spacing ;
97- } ,
159+ const isSmall = this . state . deviceSize === this . constructor . Sizes . SMALL ;
98160
99- getStyles ( ) {
100161 const styles = {
101162 root : {
102- color : this . getTheme ( ) . textColor ,
103- backgroundColor : this . getTheme ( ) . backgroundColor ,
104- borderRadius : 2 ,
105- padding : '0px ' + this . getSpacing ( ) . desktopGutter + 'px' ,
106- height : this . getSpacing ( ) . desktopSubheaderHeight ,
107- lineHeight : this . getSpacing ( ) . desktopSubheaderHeight + 'px' ,
108- minWidth : 288 ,
109- maxWidth : 568 ,
110-
111163 position : 'fixed' ,
112- zIndex : 10 ,
113- bottom : this . getSpacing ( ) . desktopGutter ,
114- marginLeft : this . getSpacing ( ) . desktopGutter ,
115-
116164 left : 0 ,
117- opacity : 0 ,
165+ display : '-webkit-box; display: -webkit-flex; display: flex' ,
166+ right : 0 ,
167+ bottom : 0 ,
168+ zIndex : 10 ,
118169 visibility : 'hidden' ,
119- transform : 'translate3d(0, 20px , 0)' ,
170+ transform : 'translate3d(0, ' + desktopSubheaderHeight + 'px , 0)',
120171 transition :
121- Transitions . easeOut ( '0ms' , 'left' , '400ms' ) + ',' +
122- Transitions . easeOut ( '400ms' , 'opacity' ) + ',' +
123172 Transitions . easeOut ( '400ms' , 'transform' ) + ',' +
124173 Transitions . easeOut ( '400ms' , 'visibility' ) ,
125174 } ,
175+ rootWhenOpen : {
176+ visibility : 'visible' ,
177+ transform : 'translate3d(0, 0, 0)' ,
178+ } ,
179+ body : {
180+ backgroundColor : backgroundColor ,
181+ padding : '0 ' + desktopGutter + 'px' ,
182+ height : desktopSubheaderHeight ,
183+ lineHeight : desktopSubheaderHeight + 'px' ,
184+ borderRadius : isSmall ? 0 : 2 ,
185+ maxWidth : isSmall ? 'inherit' : 568 ,
186+ minWidth : isSmall ? 'inherit' : 288 ,
187+ flexGrow : isSmall ? 1 : 0 ,
188+ margin : 'auto' ,
189+ } ,
190+ content : {
191+ fontSize : 14 ,
192+ color : textColor ,
193+ opacity : 0 ,
194+ transition : Transitions . easeOut ( '400ms' , 'opacity' ) ,
195+ } ,
196+ contentWhenOpen : {
197+ opacity : 1 ,
198+ transition : Transitions . easeOut ( '500ms' , 'opacity' , '100ms' ) ,
199+ } ,
126200 action : {
127- color : this . getTheme ( ) . actionColor ,
201+ color : actionColor ,
128202 float : 'right' ,
129203 marginTop : 6 ,
130204 marginRight : - 16 ,
131- marginLeft : this . getSpacing ( ) . desktopGutter ,
205+ marginLeft : desktopGutter ,
132206 backgroundColor : 'transparent' ,
133207 } ,
134- rootWhenOpen : {
135- opacity : 1 ,
136- visibility : 'visible' ,
137- transform : 'translate3d(0, 0, 0)' ,
138- transition :
139- Transitions . easeOut ( '0ms' , 'left' , '0ms' ) + ',' +
140- Transitions . easeOut ( '400ms' , 'opacity' , '0ms' ) + ',' +
141- Transitions . easeOut ( '400ms' , 'transform' , '0ms' ) + ',' +
142- Transitions . easeOut ( '400ms' , 'visibility' , '0ms' ) ,
143- } ,
144208 } ;
145209
146210 return styles ;
147211 } ,
148212
149213 render ( ) {
150- const { action, message, onActionTouchTap, style, ...others } = this . props ;
214+ const {
215+ onActionTouchTap,
216+ style,
217+ ...others ,
218+ } = this . props ;
151219 const styles = this . getStyles ( ) ;
152220
153- const rootStyles = this . state . open ?
154- this . prepareStyles ( styles . root , styles . rootWhenOpen , style ) :
155- this . prepareStyles ( styles . root , style ) ;
221+ const {
222+ open,
223+ action,
224+ message,
225+ } = this . state ;
226+
227+ const rootStyles = open ?
228+ this . mergeStyles ( styles . root , styles . rootWhenOpen , style ) :
229+ this . mergeStyles ( styles . root , style ) ;
156230
157231 let actionButton ;
158232 if ( action ) {
@@ -164,35 +238,48 @@ const Snackbar = React.createClass({
164238 ) ;
165239 }
166240
241+ const contentStyle = open ? this . mergeStyles ( styles . content , styles . contentWhenOpen ) : styles . content ;
242+
167243 return (
168- < span { ...others } style = { rootStyles } >
169- < span > { message } </ span >
170- { actionButton }
171- </ span >
244+ < div { ...others } style = { rootStyles } >
245+ < div style = { styles . body } >
246+ < div style = { contentStyle } >
247+ < span > { message } </ span >
248+ { actionButton }
249+ </ div >
250+ </ div >
251+ </ div >
172252 ) ;
173253 } ,
174254
175255 show ( ) {
176- this . setState ( { open : true } ) ;
177- if ( this . props . onShow ) this . props . onShow ( ) ;
256+ this . setState ( {
257+ open : true ,
258+ } ) ;
259+
260+ if ( this . props . onShow ) {
261+ this . props . onShow ( ) ;
262+ }
178263 } ,
179264
180265 dismiss ( ) {
181- this . _clearAutoHideTimer ( ) ;
182- this . setState ( { open : false } ) ;
183- if ( this . props . onDismiss ) this . props . onDismiss ( ) ;
184- } ,
266+ this . setState ( {
267+ open : false ,
268+ } ) ;
185269
186- _clearAutoHideTimer ( ) {
187- if ( this . _autoHideTimerId !== undefined ) {
188- this . _autoHideTimerId = clearTimeout ( this . _autoHideTimerId ) ;
270+ if ( this . props . onDismiss ) {
271+ this . props . onDismiss ( ) ;
189272 }
190273 } ,
191274
192275 _setAutoHideTimer ( ) {
193276 if ( this . props . autoHideDuration > 0 ) {
194- this . _clearAutoHideTimer ( ) ;
195- this . _autoHideTimerId = setTimeout ( ( ) => { this . dismiss ( ) ; } , this . props . autoHideDuration ) ;
277+ clearTimeout ( this . _autoHideTimerId ) ;
278+ this . _autoHideTimerId = setTimeout ( ( ) => {
279+ if ( this . isMounted ( ) ) {
280+ this . dismiss ( ) ;
281+ }
282+ } , this . props . autoHideDuration ) ;
196283 }
197284 } ,
198285
0 commit comments