From ff99ffc8f6cc9be2526f91c1aba200afd2a116d9 Mon Sep 17 00:00:00 2001 From: Kimmo Puputti Date: Wed, 14 Mar 2018 16:32:12 +0200 Subject: [PATCH 1/2] Allow passing other props to the image element --- src/components/ResponsiveImage/ResponsiveImage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ResponsiveImage/ResponsiveImage.js b/src/components/ResponsiveImage/ResponsiveImage.js index 0a73e2b4..9c465213 100644 --- a/src/components/ResponsiveImage/ResponsiveImage.js +++ b/src/components/ResponsiveImage/ResponsiveImage.js @@ -40,7 +40,7 @@ import NoImageIcon from './NoImageIcon'; import css from './ResponsiveImage.css'; const ResponsiveImage = props => { - const { className, rootClassName, alt, noImageMessage, image, nameSet, sizes } = props; + const { className, rootClassName, alt, noImageMessage, image, nameSet, sizes, ...rest } = props; const classes = classNames(rootClassName || css.root, className); if (image == null || nameSet.length === 0) { @@ -87,7 +87,7 @@ const ResponsiveImage = props => { const sizesProp = sizes ? { sizes } : {}; - return {alt}; + return {alt}; }; const { arrayOf, shape, string } = PropTypes; From e721889de40f643a0bbe81792c7eedcf02602712 Mon Sep 17 00:00:00 2001 From: Kimmo Puputti Date: Wed, 14 Mar 2018 16:32:27 +0200 Subject: [PATCH 2/2] Show loading spinner when image is being loaded --- .../ImageCarousel/ImageCarousel.css | 20 ++++++++++ src/components/ImageCarousel/ImageCarousel.js | 39 ++++++++++++++++--- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/components/ImageCarousel/ImageCarousel.css b/src/components/ImageCarousel/ImageCarousel.css index 6584a0f7..92bafc6b 100644 --- a/src/components/ImageCarousel/ImageCarousel.css +++ b/src/components/ImageCarousel/ImageCarousel.css @@ -96,7 +96,27 @@ } } +.loading { + position: absolute; + top: 50%; + left: 50%; + width: 50px; + height: 50px; + margin-left: -25px; + margin-top: -25px; + opacity: 0; +} + +.loadingVisible { + opacity: 1; + transition: opacity var(--transitionStyle); +} + .image { /* Fit image in the available space as big as possible, keeping the aspect ratio */ object-fit: contain; } + +.imageLoading { + opacity: 0.5; +} diff --git a/src/components/ImageCarousel/ImageCarousel.js b/src/components/ImageCarousel/ImageCarousel.js index 4183916e..0e9aa72e 100644 --- a/src/components/ImageCarousel/ImageCarousel.js +++ b/src/components/ImageCarousel/ImageCarousel.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { injectIntl, intlShape } from 'react-intl'; import classNames from 'classnames'; -import { ResponsiveImage } from '../../components'; +import { ResponsiveImage, IconSpinner } from '../../components'; import { propTypes } from '../../util/types'; import css from './ImageCarousel.css'; @@ -18,7 +18,7 @@ const imageScaledXLarge = 'scaled-xlarge'; // width 2400 class ImageCarousel extends Component { constructor(props) { super(props); - this.state = { selectedImageIndex: 0 }; + this.state = { selectedImageIndex: 0, selectedImageLoaded: false }; this.onKeyUp = this.onKeyUp.bind(this); this.prev = this.prev.bind(this); this.next = this.next.bind(this); @@ -38,16 +38,22 @@ class ImageCarousel extends Component { } prev() { const count = this.props.images.length; + if (count < 2) { + return; + } this.setState(prevState => { const newIndex = count > 0 ? (count + prevState.selectedImageIndex - 1) % count : 0; - return { selectedImageIndex: newIndex }; + return { selectedImageIndex: newIndex, selectedImageLoaded: false }; }); } next() { const count = this.props.images.length; + if (count < 2) { + return; + } this.setState(prevState => { const newIndex = count > 0 ? (count + prevState.selectedImageIndex + 1) % count : 0; - return { selectedImageIndex: newIndex }; + return { selectedImageIndex: newIndex, selectedImageLoaded: false }; }); } render() { @@ -76,13 +82,36 @@ class ImageCarousel extends Component { } ); + const markImageLoaded = index => () => { + this.setState(prevState => { + if (prevState.selectedImageIndex === index) { + // Only mark the image loaded if the current index hasn't + // changed, i.e. user hasn't already changed to another + // image index. + return { selectedImageLoaded: true }; + } + return {}; + }); + }; + + const currentImageIsLoaded = images.length === 0 || this.state.selectedImageLoaded; + const loadingIconClasses = classNames(css.loading, { + [css.loadingVisible]: !currentImageIsLoaded, + }); + const imageClasses = classNames(css.image, { + [css.imageLoading]: !currentImageIsLoaded, + }); + return (
+