From e8519bdddd31a33ace25ffbcb73273c1573e9c33 Mon Sep 17 00:00:00 2001
From: eug-vs <eug-vs@keemail.me>
Date: Fri, 14 Aug 2020 16:51:19 +0300
Subject: feat: apply cool transitions to Image

---
 src/components/Image/Image.tsx | 55 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 45 insertions(+), 10 deletions(-)

(limited to 'src/components/Image/Image.tsx')

diff --git a/src/components/Image/Image.tsx b/src/components/Image/Image.tsx
index 7736e8a..1898716 100644
--- a/src/components/Image/Image.tsx
+++ b/src/components/Image/Image.tsx
@@ -1,14 +1,19 @@
-import React, { useState, useCallback } from 'react';
+import React, { useState, useCallback, useMemo } from 'react';
 import { makeStyles } from '@material-ui/core/styles';
 import CircularProgress from '@material-ui/core/CircularProgress';
 import ErrorIcon from '@material-ui/icons/BrokenImage';
+import grey from '@material-ui/core/colors/grey';
 
 interface PropTypes {
   src?: string;
   alt?: string;
   className?: string;
+  animationDuration?: number;
+  disableLoading?: boolean;
 }
 
+type Status = 'success' | 'loading' | 'error';
+
 const useStyles = makeStyles(theme => ({
   container: {
     width: '100%',
@@ -16,12 +21,35 @@ const useStyles = makeStyles(theme => ({
     display: 'flex',
     alignItems: 'center',
     justifyContent: 'center'
+  },
+  success: {
+    opacity: '100%',
+    filterBrightness: '100%',
+    filterSaturate: '100%'
+  },
+  loading: {
+    opacity: 0,
+    filterBrightness: 0,
+    filterSaturate: '20%',
+    position: 'absolute'
+  },
+  error: {
+    display: 'none'
+  },
+  errorIcon: {
+    color: grey[300],
+    width: theme.spacing(6),
+    height: theme.spacing(6)
   }
 }));
 
-type Status = 'success' |'loading' | 'error';
-
-const Image: React.FC<PropTypes> = ({ src, alt, className }) => {
+const Image: React.FC<PropTypes> = React.memo(({
+  src,
+  alt,
+  className,
+  animationDuration = 1000,
+  disableLoading = false
+}) => {
   const classes = useStyles();
   const [status, setStatus] = useState<Status>('loading');
 
@@ -33,12 +61,18 @@ const Image: React.FC<PropTypes> = ({ src, alt, className }) => {
     setStatus('error');
   }, [setStatus]);
 
+  const transition = useMemo(() => `
+    filterBrightness ${animationDuration * 0.75}ms cubic-bezier(0.4, 0.0, 0.2, 1),
+    filterSaturate ${animationDuration}ms cubic-bezier(0.4, 0.0, 0.2, 1),
+    opacity ${animationDuration / 2}ms cubic-bezier(0.4, 0.0, 0.2, 1)
+  `, [animationDuration]);
+
   const image = (
     <img
       src={src}
       alt={alt}
-      className={className}
-      style={{ display: status === 'success' ? 'inline' : 'none' }}
+      className={`${className} ${classes[status]}`}
+      style={{ transition }}
       onLoad={handleLoad}
       onError={handleError}
     />
@@ -52,14 +86,15 @@ const Image: React.FC<PropTypes> = ({ src, alt, className }) => {
           <div className={classes.container}>
             {
               (status === 'error' || !src)
-              ? <ErrorIcon fontSize="large" />
-              : <CircularProgress color="primary" />
+                ? <ErrorIcon className={classes.errorIcon} />
+                : (!disableLoading && <CircularProgress color="primary" />)
             }
           </div>
-      )}
+        )
+      }
     </>
   );
-};
+});
 
 export default Image;
 
-- 
cgit v1.2.3

