11import * as React from "react" ;
2- import * as TypeStyle from "typestyle" ;
2+ import { classes as classNames } from "typestyle" ;
33
4+ import { default as classes } from "./classes" ;
45import { clamp , isFunction } from "./utils" ;
56
67export enum Interaction {
78 None = "NONE" ,
9+ Resize = "RESIZE" ,
810 Hover = "HOVER" ,
911 Active = "ACTIVE" ,
10- Resize = "RESIZE" ,
1112}
1213
1314export interface ILayeredImageProps extends React . HTMLProps < HTMLDivElement > {
1415 layers : Array < string > ;
15- aspectRatio : number ;
16+ aspectRatio ? : number ;
1617 borderRadius ?: React . CSSProperties [ "borderRadius" ] ;
1718 transitionDuration ?: React . CSSProperties [ "transitionDuration" ] ;
1819 transitionTimingFunction ?: React . CSSProperties [ "transitionTimingFunction" ] ;
@@ -41,14 +42,14 @@ interface ILayeredImageStyles {
4142
4243export default class LayeredImage extends React . Component < ILayeredImageProps , ILayeredImageState > {
4344 public static defaultProps : Partial < ILayeredImageProps > = {
44- aspectRatio : 0.75 ,
45- borderRadius : 5 ,
45+ aspectRatio : 16 / 10 ,
46+ borderRadius : 6 ,
4647 transitionDuration : 0.2 ,
4748 transitionTimingFunction : "ease-out" ,
4849 lightColor : "#fff" ,
49- lightOpacity : 0.1 ,
50+ lightOpacity : 0.2 ,
5051 shadowColor : "#000" ,
51- shadowOpacity : 0.4 ,
52+ shadowOpacity : 0.6 ,
5253 } ;
5354
5455 public state : ILayeredImageState = {
@@ -89,33 +90,37 @@ export default class LayeredImage extends React.Component<ILayeredImageProps, IL
8990 style,
9091 } = this . props ;
9192 const { width, loaded } = this . state ;
93+ const staticStyles = this . getStaticStyles ( ) ;
9294 const styles : ILayeredImageStyles = {
9395 root : {
94- borderRadius : borderRadius ,
96+ borderRadius,
9597 transform : `perspective(${ width * 3 } px)` ,
98+ ...staticStyles . root ,
9699 } ,
97100 container : {
98- borderRadius : borderRadius ,
99- transition : `transform ${ transitionDuration } s ${ transitionTimingFunction } ` ,
101+ borderRadius,
102+ transitionTimingFunction,
103+ ...staticStyles . container ,
100104 } ,
101105 layers : {
102- borderRadius : borderRadius ,
106+ borderRadius,
107+ ...staticStyles . layers ,
103108 } ,
104109 layer : {
105- transition : `transform ${ transitionDuration } s ${ transitionTimingFunction } ,
106- opacity ${ transitionDuration * 3 } s ${ transitionTimingFunction } ` ,
110+ transitionDuration : `${ transitionDuration } s, ${ transitionDuration * 3 } s` ,
111+ transitionTimingFunction,
112+ ...staticStyles . layer ,
107113 } ,
108114 light : {
109- borderRadius : borderRadius ,
110- backgroundImage : `linear-gradient(180deg, ${ lightColor } 0%, transparent 80%)` ,
115+ borderRadius,
111116 opacity : lightOpacity ,
117+ ...staticStyles . light ,
112118 } ,
113119 shadow : {
114- borderRadius : borderRadius * 2 ,
115- boxShadow : `0 8px 20px ${ shadowColor } , 0 2px 4px ${ shadowColor } ` ,
120+ borderRadius,
116121 opacity : shadowOpacity ,
117- transition : `box-shadow ${ transitionDuration } s ${ transitionTimingFunction } ,
118- opacity ${ transitionDuration } s ${ transitionTimingFunction } ` ,
122+ transitionTimingFunction,
123+ ... staticStyles . shadow ,
119124 } ,
120125 } ;
121126
@@ -129,7 +134,7 @@ export default class LayeredImage extends React.Component<ILayeredImageProps, IL
129134 onTouchStart = { this . handleTouchInteraction ( Interaction . Hover ) }
130135 onTouchMove = { this . handleTouchInteraction ( Interaction . Hover ) }
131136 onTouchEnd = { this . handleInteractionEnd }
132- className = { TypeStyle . classes ( classes . root , className ) }
137+ className = { classNames ( classes . root , className ) }
133138 style = { { ...styles . root , ...style } }
134139 ref = { this . refHandlers . root }
135140 >
@@ -211,11 +216,32 @@ export default class LayeredImage extends React.Component<ILayeredImageProps, IL
211216 this . elements . container . offsetWidth ||
212217 this . elements . container . clientWidth ||
213218 this . elements . container . scrollWidth ;
214- const height = Math . round ( width * aspectRatio ) ;
219+ const height = Math . round ( width / aspectRatio ) ;
215220
216221 return { width, height } ;
217222 } ;
218223
224+ private getStaticStyles = ( ) : ILayeredImageStyles => {
225+ const { transitionDuration, lightColor, shadowColor } = this . props ;
226+
227+ return {
228+ container : {
229+ transform : "none" ,
230+ transitionDuration : `${ transitionDuration } s` ,
231+ } ,
232+ layer : {
233+ transform : "none" ,
234+ } ,
235+ light : {
236+ backgroundImage : `linear-gradient(180deg, ${ lightColor } 0%, transparent 80%)` ,
237+ } ,
238+ shadow : {
239+ boxShadow : `0 10px 30px ${ shadowColor } , 0 6px 10px ${ shadowColor } ` ,
240+ transitionDuration : `${ transitionDuration } s` ,
241+ } ,
242+ } ;
243+ } ;
244+
219245 private computeStyles = (
220246 options : {
221247 interaction : Interaction ;
@@ -229,6 +255,7 @@ export default class LayeredImage extends React.Component<ILayeredImageProps, IL
229255 const { interaction = this . state . interaction , aspectRatio } = options ;
230256 const { layers, transitionDuration, lightColor, shadowColor } = this . props ;
231257 const { width, height } = interaction === Interaction . Resize ? this . getDimensions ( aspectRatio ) : this . state ;
258+ const staticStyles = this . getStaticStyles ( ) ;
232259
233260 const bodyScrollTop =
234261 document . body . scrollTop ||
@@ -251,26 +278,14 @@ export default class LayeredImage extends React.Component<ILayeredImageProps, IL
251278 const lightAngle = Math . atan2 ( containerCenterY , containerCenterX ) * 180 / Math . PI - 90 ;
252279
253280 const computedStyles : ILayeredImageStyles = {
254- [ Interaction . None ] : {
255- container : {
256- transform : "none" ,
257- transitionDuration : `${ transitionDuration } s` ,
258- } ,
259- layer : {
260- transform : "none" ,
261- } ,
262- light : {
263- backgroundImage : `linear-gradient(180deg, ${ lightColor } 0%, transparent 80%)` ,
264- } ,
265- shadow : {
266- boxShadow : `0 8px 20px ${ shadowColor } , 0 2px 4px ${ shadowColor } ` ,
267- transitionDuration : `${ transitionDuration } s` ,
268- } ,
269- } ,
281+ [ Interaction . None ] : { ...staticStyles } ,
282+ [ Interaction . Resize ] : { root : { height : `${ height } px` } } ,
270283 [ Interaction . Hover ] : {
271284 container : {
272285 transform : `rotateX(${ - clamp ( containerRotationX , - 8 , 8 ) } deg)
273286 rotateY(${ - clamp ( containerRotationY , - 8 , 8 ) } deg)
287+ translateX(${ - layerTranslationX * 6 } px)
288+ translateY(${ - layerTranslationY * 6 } px)
274289 scale(1.1)` ,
275290 } ,
276291 layer : ( index : number ) => ( {
@@ -301,15 +316,10 @@ export default class LayeredImage extends React.Component<ILayeredImageProps, IL
301316 backgroundImage : `linear-gradient(${ lightAngle } deg, ${ lightColor } 0%, transparent 80%)` ,
302317 } ,
303318 shadow : {
304- boxShadow : `0 8px 20px ${ shadowColor } , 0 2px 4px ${ shadowColor } ` ,
319+ ... staticStyles . shadow ,
305320 transitionDuration : "0.075s" ,
306321 } ,
307322 } ,
308- [ Interaction . Resize ] : {
309- root : {
310- height : `${ height } px` ,
311- } ,
312- } ,
313323 } [ interaction ] ;
314324
315325 if ( preventDefault ) {
@@ -339,49 +349,3 @@ export default class LayeredImage extends React.Component<ILayeredImageProps, IL
339349 } ) ;
340350 } ;
341351}
342-
343- const classes = {
344- root : TypeStyle . style ( {
345- position : "relative" ,
346- width : "100%" ,
347- transformStyle : "preserve-3d" ,
348- cursor : "pointer" ,
349- "-webkit-tap-highlight-color" : "rgba(0, 0, 0, 0)" ,
350- } ) ,
351- container : TypeStyle . style ( {
352- position : "absolute" ,
353- width : "100%" ,
354- height : "100%" ,
355- transformStyle : "preserve-3d" ,
356- } ) ,
357- layers : TypeStyle . style ( {
358- position : "absolute" ,
359- width : "100%" ,
360- height : "100%" ,
361- transformStyle : "preserve-3d" ,
362- overflow : "hidden" ,
363- background : "black" ,
364- } ) ,
365- layer : TypeStyle . style ( {
366- position : "absolute" ,
367- width : "100%" ,
368- height : "100%" ,
369- backgroundRepeat : "no-repeat" ,
370- backgroundPosition : "center" ,
371- backgroundColor : "transparent" ,
372- backgroundSize : "cover" ,
373- opacity : 0 ,
374- } ) ,
375- light : TypeStyle . style ( {
376- position : "absolute" ,
377- width : "100%" ,
378- height : "100%" ,
379- } ) ,
380- shadow : TypeStyle . style ( {
381- position : "absolute" ,
382- width : "100%" ,
383- height : "100%" ,
384- transform : "translateZ(-10px) scale(0.98)" ,
385- transitionProperty : "transform, box-shadow" ,
386- } ) ,
387- } ;
0 commit comments