@@ -18,7 +18,7 @@ export default React.createClass({
18
18
function rangeCheck ( props , propName , componentName ) {
19
19
if ( props [ propName ] > props . numItems ) {
20
20
return new Error ( 'Carousel must be initialized with ' +
21
- 'enough items to fill every slot.' )
21
+ 'enough items to fill every slot.' ) ;
22
22
}
23
23
}
24
24
@@ -31,16 +31,8 @@ export default React.createClass({
31
31
return error ;
32
32
33
33
} ,
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
44
36
} ,
45
37
46
38
getDefaultProps ( ) {
@@ -124,20 +116,22 @@ export default React.createClass({
124
116
} ,
125
117
126
118
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 ) {
131
121
CarouselActions . respawn ( ) ;
132
122
}
123
+ event . stopPropagation ( ) ;
133
124
} ,
134
125
135
126
handleReset ( ) {
136
127
CarouselActions . reset ( this . props . numItems ) ;
137
128
} ,
138
129
139
- handleClear ( ) {
130
+ handleClear ( event ) {
140
131
CarouselActions . clear ( ) ;
132
+ // don't let clicks on the 'clear' button bubble up to the generic
133
+ // interaction handler.
134
+ event . stopPropagation ( ) ;
141
135
} ,
142
136
143
137
slideBackward ( ) {
@@ -184,36 +178,44 @@ export default React.createClass({
184
178
// https://vimeo.com/channels/684289/116209150
185
179
staticStyles : {
186
180
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
198
190
} ,
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
199
197
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()
202
201
} ,
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'
205
211
} ,
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 : {
215
213
textAlign : 'center' ,
216
- fontSize : 50
214
+ fontSize : 50 ,
215
+ fontWeight : 100
216
+ } ,
217
+ item : {
218
+ display : 'inline-block'
217
219
} ,
218
220
leftArrow : {
219
221
width : 0 ,
@@ -236,8 +238,11 @@ export default React.createClass({
236
238
borderLeft : '15px solid black'
237
239
} ,
238
240
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.
241
246
button : { // fake Twitter Bootstrap button
242
247
display : 'inlineBlock' ,
243
248
webkitAppearance : 'button' ,
@@ -253,26 +258,33 @@ export default React.createClass({
253
258
} ,
254
259
255
260
render ( ) {
256
- // suppress render until the backing store is initialized
257
- if ( this . state . items === undefined ) return < div />
258
-
259
261
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 )
266
267
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 ) ;
273
284
274
285
// calculate the slider's left offset and supply an appropriate
275
286
// transition: ease while sliding, snap before re-render.
287
+ const itemWidth = 100 / this . props . numSlots ;
276
288
let slidingStyle ;
277
289
switch ( this . state . sliding ) {
278
290
case this . enums . sliding . FORWARD :
@@ -284,12 +296,10 @@ export default React.createClass({
284
296
transition : `left ${ this . props . slideDuration } ms ease` } ;
285
297
break ;
286
298
default :
287
- slidingStyle = { left : `-${ itemWidth } %` ,
288
- transition : 'none' } ;
299
+ slidingStyle = { left : `-${ itemWidth } %` , transition : 'none' } ;
289
300
}
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
293
303
dynamicStyles . item = Object . assign ( { } ,
294
304
this . staticStyles . item ,
295
305
{ width : `${ itemWidth } %` } ) ;
@@ -299,10 +309,11 @@ export default React.createClass({
299
309
const circularized = Immutable . Repeat ( withIndices ) . flatten ( 1 ) ;
300
310
const slice = circularized . slice ( this . state . offsetIndex ,
301
311
this . state . offsetIndex + this . props . numSlots + 2 ) ;
312
+ // render them
302
313
let items = slice . map ( ( [ shape , storeIndex ] , sliceIndex ) =>
303
314
< 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
306
317
index = { storeIndex }
307
318
style = { dynamicStyles . item }
308
319
hp = { shape . hp }
@@ -311,41 +322,45 @@ export default React.createClass({
311
322
// iterables in JSX, but for now we must
312
323
// convert to the built-in Array type.
313
324
314
- return < div style = { { position : 'relative' } }
325
+ return < div style = { this . staticStyles . container }
315
326
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 }
323
337
</ 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 >
336
344
</ div >
337
345
</ div >
338
- < div style = { this . staticStyles . buttonGroup } >
346
+ < div style = { this . staticStyles . endCap } >
339
347
< 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 } />
348
352
</ 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 >
349
364
</ div > ;
350
365
}
351
366
} ) ;
0 commit comments