@@ -18,7 +18,7 @@ export default React.createClass({
1818 function rangeCheck ( props , propName , componentName ) {
1919 if ( props [ propName ] > props . numItems ) {
2020 return new Error ( 'Carousel must be initialized with ' +
21- 'enough items to fill every slot.' )
21+ 'enough items to fill every slot.' ) ;
2222 }
2323 }
2424
@@ -31,16 +31,8 @@ export default React.createClass({
3131 return error ;
3232
3333 } ,
34- slideDuration : React . PropTypes . number ,
35- fullscreen : React . PropTypes . bool
36- } ,
37-
38- validateSlots ( props , propName , componentName ) {
39- React . PropTypes . number ( props , propName , componentName ) ;
40- if ( props [ propName ] > props . numItems ) {
41- return new Error ( 'Carousel may not be initialized with more slots' +
42- 'than items' )
43- }
34+ respawnThreshold : React . PropTypes . number ,
35+ slideDuration : React . PropTypes . number
4436 } ,
4537
4638 getDefaultProps ( ) {
@@ -124,20 +116,22 @@ export default React.createClass({
124116 } ,
125117
126118 handleGenericInteraction ( ) {
127- this . setState ( { genericInteractions : this . state . genericInteractions + 1 } )
128- // don't respawn if the user's first interaction is with the
129- // 'clear' button!
130- if ( ( this . state . genericInteractions + 1 ) % this . props . respawnThreshold === 0 ) {
119+ this . setState ( { genericInteractions : this . state . genericInteractions + 1 } ) ;
120+ if ( this . state . genericInteractions % this . props . respawnThreshold === 0 ) {
131121 CarouselActions . respawn ( ) ;
132122 }
123+ event . stopPropagation ( ) ;
133124 } ,
134125
135126 handleReset ( ) {
136127 CarouselActions . reset ( this . props . numItems ) ;
137128 } ,
138129
139- handleClear ( ) {
130+ handleClear ( event ) {
140131 CarouselActions . clear ( ) ;
132+ // don't let clicks on the 'clear' button bubble up to the generic
133+ // interaction handler.
134+ event . stopPropagation ( ) ;
141135 } ,
142136
143137 slideBackward ( ) {
@@ -184,36 +178,44 @@ export default React.createClass({
184178 // https://vimeo.com/channels/684289/116209150
185179 staticStyles : {
186180 container : {
187- display : 'table-row' // flexbox is the modern way to build
188- } , // this type of layout, but display: table
189- verticalAligner : { // and friends work adequately for this
190- display : 'table-cell' , // case and enjoy ubiquitous support.
191- verticalAlign : 'middle'
192- } ,
193- overflowConcealer : {
194- display : 'table-cell' , // 100% of container width after
195- width : '100%' , // accounting for the navigational buttons
196- overflowX : 'hidden' ,
197- overflowY : 'hidden'
181+ position : 'relative' , // we'll position the reset and clear
182+ display : 'flex' , // buttons relative to the outer div
183+ alignItems : 'center' ,
184+ height : '100%' , // occupy the full height of our parent
185+ overflow : 'hidden' // rather than the natural height of the
186+ } , // tallest carousel item
187+ endCap : {
188+ flexShrink : 0 ,
189+ zIndex : 100
198190 } ,
191+ stock : {
192+ flexGrow : 1 ,
193+ display : 'flex' ,
194+ alignItems : 'center' ,
195+ position : 'relative' // the stock is the reference for
196+ } , // the slider and the 'game over' message
199197 slider : {
200- position : 'relative' , // later, we will calculate how much to
201- whiteSpace : 'nowrap' // shift the slider relative to its parent
198+ flexGrow : 1 ,
199+ position : 'relative' , // we will calculate how much to offset
200+ whiteSpace : 'nowrap' // the slider in render()
202201 } ,
203- item : {
204- display : 'inline-block'
202+ messageContainer : {
203+ position : 'absolute' ,
204+ top : 0 ,
205+ right : 0 ,
206+ bottom : 0 ,
207+ left : 0 ,
208+ display : 'flex' ,
209+ justifyContent : 'center' ,
210+ alignItems : 'center'
205211 } ,
206- gameOverVerticalAligner : { // flexbox would have obviated the
207- position : 'absolute' , // 1 need for this non-semantic wrapper
208- top : '50%' , // 2 div and these five numbered style
209- width : '100%' // 3 properties
210- } ,
211- gameOverText : {
212- position : 'absolute' , // 4
213- top : '-0.5em' , // 5
214- width : '100%' ,
212+ message : {
215213 textAlign : 'center' ,
216- fontSize : 50
214+ fontSize : 50 ,
215+ fontWeight : 100
216+ } ,
217+ item : {
218+ display : 'inline-block'
217219 } ,
218220 leftArrow : {
219221 width : 0 ,
@@ -236,8 +238,11 @@ export default React.createClass({
236238 borderLeft : '15px solid black'
237239 } ,
238240 buttonGroup : {
239- textAlign : 'right'
240- } ,
241+ position : 'absolute' ,
242+ bottom : 4 ,
243+ right : 4 ,
244+ zIndex : 100 // setting negative zIndex on the carousel items
245+ } , // breaks their onClick handlers.
241246 button : { // fake Twitter Bootstrap button
242247 display : 'inlineBlock' ,
243248 webkitAppearance : 'button' ,
@@ -253,26 +258,33 @@ export default React.createClass({
253258 } ,
254259
255260 render ( ) {
256- // suppress render until the backing store is initialized
257- if ( this . state . items === undefined ) return < div />
258-
259261 const dynamicStyles = { } ;
260- const itemWidth = 100 / this . props . numSlots ;
261- dynamicStyles . slider = Object . assign ( { } ,
262- this . staticStyles . slider
263- // {height: 0,
264- // paddingBottom: `${itemWidth}%` }
265- )
262+ // allow our caller to set styles on us, provided they don't
263+ // conflict with the ones we neeed.
264+ dynamicStyles . container = Object . assign ( { } ,
265+ this . props . style ,
266+ this . staticStyles . container )
266267
267- // } else if (this.state.gameOver) {
268- // items = <div style={this.staticStyles.gameOverVerticalAligner}>
269- // <div style={this.staticStyles.gameOverText}>
270- // Game Over
271- // </div>
272- // </div>
268+ // suppress render until the backing store is initialized
269+ if ( this . state . items === undefined ) {
270+ return < div style = { dynamicStyles . container } /> ;
271+ }
272+
273+ let messageStyle ;
274+ if ( this . state . gameOver ) {
275+ messageStyle = { transform : 'scale(1,1)' ,
276+ transition : 'transform 450ms cubic-bezier(.4,1.4,.4,1)' } ;
277+ } else {
278+ messageStyle = { transform : 'scale(0,0)' ,
279+ transition : 'none' } ;
280+ }
281+ dynamicStyles . message = Object . assign ( { } ,
282+ this . staticStyles . message ,
283+ messageStyle ) ;
273284
274285 // calculate the slider's left offset and supply an appropriate
275286 // transition: ease while sliding, snap before re-render.
287+ const itemWidth = 100 / this . props . numSlots ;
276288 let slidingStyle ;
277289 switch ( this . state . sliding ) {
278290 case this . enums . sliding . FORWARD :
@@ -284,12 +296,10 @@ export default React.createClass({
284296 transition : `left ${ this . props . slideDuration } ms ease` } ;
285297 break ;
286298 default :
287- slidingStyle = { left : `-${ itemWidth } %` ,
288- transition : 'none' } ;
299+ slidingStyle = { left : `-${ itemWidth } %` , transition : 'none' } ;
289300 }
290- Object . assign ( dynamicStyles . slider , slidingStyle ) ;
291-
292- // get the items we need and render them.
301+ dynamicStyles . slider = Object . assign ( { } , this . staticStyles . slider , slidingStyle ) ;
302+ // get the items we need
293303 dynamicStyles . item = Object . assign ( { } ,
294304 this . staticStyles . item ,
295305 { width : `${ itemWidth } %` } ) ;
@@ -299,10 +309,11 @@ export default React.createClass({
299309 const circularized = Immutable . Repeat ( withIndices ) . flatten ( 1 ) ;
300310 const slice = circularized . slice ( this . state . offsetIndex ,
301311 this . state . offsetIndex + this . props . numSlots + 2 ) ;
312+ // render them
302313 let items = slice . map ( ( [ shape , storeIndex ] , sliceIndex ) =>
303314 < CarouselItem key = { storeIndex + // a unique and
304- Math . floor ( sliceIndex / // stable key saves
305- this . state . items . size ) } // DOM operations
315+ Math . floor ( sliceIndex / // stable key
316+ this . state . items . size ) } // avoids redraws
306317 index = { storeIndex }
307318 style = { dynamicStyles . item }
308319 hp = { shape . hp }
@@ -311,41 +322,45 @@ export default React.createClass({
311322 // iterables in JSX, but for now we must
312323 // convert to the built-in Array type.
313324
314- return < div style = { { position : 'relative' } }
325+ return < div style = { this . staticStyles . container }
315326 onClick = { this . handleGenericInteraction } >
316- < div style = { this . staticStyles . container } >
317- < div style = { this . staticStyles . verticalAligner } >
318- < input type = "button"
319- style = { this . staticStyles . leftArrow }
320- disabled = { this . state . sliding !==
321- this . enums . sliding . STOPPED }
322- onClick = { this . slideBackward } />
327+ < div style = { this . staticStyles . endCap } >
328+ < input type = "button"
329+ style = { this . staticStyles . leftArrow }
330+ disabled = { this . state . sliding !==
331+ this . enums . sliding . STOPPED }
332+ onClick = { this . slideBackward } />
333+ </ div >
334+ < div style = { this . staticStyles . stock } >
335+ < div style = { dynamicStyles . slider } >
336+ { items }
323337 </ div >
324- < div style = { this . staticStyles . overflowConcealer } >
325- < div style = { dynamicStyles . slider } >
326- { items }
327- </ div >
328- Game Over
329- </ div >
330- < div style = { this . staticStyles . verticalAligner } >
331- < input type = "button"
332- style = { this . staticStyles . rightArrow }
333- disabled = { this . state . sliding !==
334- this . enums . sliding . STOPPED }
335- onClick = { this . slideForward } />
338+ < div style = { this . staticStyles . messageContainer } >
339+ < span style = { dynamicStyles . message } >
340+ { 'Thanks for Playing!' }
341+ < br />
342+ { 'April Arcus <3 Patreon' }
343+ </ span >
336344 </ div >
337345 </ div >
338- < div style = { this . staticStyles . buttonGroup } >
346+ < div style = { this . staticStyles . endCap } >
339347 < input type = "button"
340- style = { this . staticStyles . button }
341- value = "Reset"
342- onClick = { this . handleReset } />
343- < input type = "button"
344- style = { this . staticStyles . button }
345- value = "Clear"
346- disabled = { this . state . gameOver }
347- onClick = { this . handleClear } />
348+ style = { this . staticStyles . rightArrow }
349+ disabled = { this . state . sliding !==
350+ this . enums . sliding . STOPPED }
351+ onClick = { this . slideForward } />
348352 </ div >
353+ < div style = { this . staticStyles . buttonGroup } >
354+ < input type = "button"
355+ style = { this . staticStyles . button }
356+ value = "Reset"
357+ onClick = { this . handleReset } />
358+ < input type = "button"
359+ style = { this . staticStyles . button }
360+ value = "Clear"
361+ disabled = { this . state . gameOver }
362+ onClick = { this . handleClear } />
363+ </ div >
349364 </ div > ;
350365 }
351366} ) ;
0 commit comments