diff options
-rw-r--r-- | src/components/Image/BackgroundImage.tsx | 8 | ||||
-rw-r--r-- | src/components/Image/Image.tsx | 55 |
2 files changed, 49 insertions, 14 deletions
diff --git a/src/components/Image/BackgroundImage.tsx b/src/components/Image/BackgroundImage.tsx index 824f667..e749d10 100644 --- a/src/components/Image/BackgroundImage.tsx +++ b/src/components/Image/BackgroundImage.tsx @@ -7,7 +7,7 @@ interface PropTypes { alt?: string; } -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles({ root: { position: 'absolute', width: '100%', @@ -19,7 +19,7 @@ const useStyles = makeStyles(theme => ({ width: '100%', height: '100%' } -})); +}); const BackgroundImage: React.FC<PropTypes> = ({ src, alt }) => { const classes = useStyles(); @@ -28,8 +28,8 @@ const BackgroundImage: React.FC<PropTypes> = ({ src, alt }) => { <picture className={classes.root}> <Image src={src} alt={alt} className={classes.image} /> </picture> - ) -} + ); +}; export default BackgroundImage; 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; |