diff --git a/package.json b/package.json index da38ebb..8fac24e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-gallery-carousel", - "version": "0.3.0", + "version": "0.4.0", "description": "Mobile-friendly Carousel with batteries included (supporting touch, mouse emulation, lazy loading, thumbnails, fullscreen, RTL, keyboard navigation and customisations).", "author": "yifaneye", "license": "MIT", diff --git a/src/components/Carousel/Carousel.js b/src/components/Carousel/Carousel.js index da42737..374b404 100644 --- a/src/components/Carousel/Carousel.js +++ b/src/components/Carousel/Carousel.js @@ -406,6 +406,20 @@ const GalleryCarousel = (props, ref) => { isMaximized ); + /* check whether fallback image (if specified) returns an ok status */ + const [fallbackImg, setFallbackImg] = useState(null); + useEffect(() => { + fetch(props.fallbackImg) + .then((res) => { + if (res.ok) { + setFallbackImg(props.fallbackImg); + } + }) + .catch((_reason) => { + setFallbackImg(null); + }); + }); + const leftButton = widgetSettings.hasLeftButton && ( { shouldLazyLoad={props.shouldLazyLoad} curIndex={slides.curIndex} callbacks={goToIndexCallbacksObject} + fallbackImg={fallbackImg} /> ); @@ -564,6 +579,7 @@ const GalleryCarousel = (props, ref) => { widgetsHasShadow={props.widgetsHasShadow} hasCaptions={settings.hasCaptions} curIndex={slides.curIndex} + fallbackImg={fallbackImg} /> {widgets} diff --git a/src/components/Carousel/props.js b/src/components/Carousel/props.js index 78c38a8..91be847 100644 --- a/src/components/Carousel/props.js +++ b/src/components/Carousel/props.js @@ -48,6 +48,7 @@ export const propTypes = { hasDotButtonsAtMax: largeWidgetPositions, hasCaptionsAtMax: largeWidgetPositions, hasThumbnailsAtMax: PropTypes.bool, + fallbackImg: PropTypes.string, leftIcon: PropTypes.node, rightIcon: PropTypes.node, playIcon: PropTypes.node, diff --git a/src/components/Image/Image.js b/src/components/Image/Image.js index f5b1c69..d614efa 100644 --- a/src/components/Image/Image.js +++ b/src/components/Image/Image.js @@ -39,9 +39,13 @@ const LazyLoadedImage = (props) => { let { src, srcset, alt, thumbnail, ...otherImageProps } = props.image; - src = isInViewport && !hasError ? src : PLACEHOLDER_IMAGE; + src = + isInViewport && !hasError ? src : props.fallbackImg ?? PLACEHOLDER_IMAGE; srcset = isInViewport && !hasError ? srcset : null; - thumbnail = isInViewport && !hasError ? thumbnail : PLACEHOLDER_IMAGE; + thumbnail = + isInViewport && !hasError + ? thumbnail + : props.fallbackImg ?? PLACEHOLDER_IMAGE; return ( <> @@ -81,11 +85,16 @@ export const Image = (props) => { const { src, alt, srcset, thumbnail, ...otherImageProps } = props.image; + const handleError = (event) => { + event.target.src = props.fallbackImg ?? PLACEHOLDER_IMAGE; + }; + const image = props.shouldLazyLoad ? ( ) : ( { +const handleError = (event, fallbackImg) => { // permanently replace the image with the fallback image - event.target.src = PLACEHOLDER_IMAGE; + event.target.src = fallbackImg ?? PLACEHOLDER_IMAGE; }; const LazyLoadedImageThumbnail = (props) => { @@ -30,7 +30,7 @@ const LazyLoadedImageThumbnail = (props) => { src={src} alt={props.alt} aria-label={props.alt} - onError={handleError} + onError={(event) => handleError(event, props.fallbackImg)} /> ); }; @@ -38,7 +38,8 @@ const LazyLoadedImageThumbnail = (props) => { LazyLoadedImageThumbnail.propTypes = { thumbnailsContainerRef: elementRef.isRequired, src: PropTypes.string.isRequired, - alt: PropTypes.string + alt: PropTypes.string, + fallbackImg: PropTypes.string }; export const ImageThumbnail = (props) => { @@ -52,6 +53,7 @@ export const ImageThumbnail = (props) => { thumbnailsContainerRef={props.thumbnailsContainerRef} src={src} alt={alt} + fallbackImg={props.fallbackImg} /> ); @@ -62,7 +64,7 @@ export const ImageThumbnail = (props) => { alt={alt} aria-label={alt} loading='auto' - onError={handleError} + onError={(event) => handleError(event, props.fallbackImg)} /> ); }; @@ -70,5 +72,6 @@ export const ImageThumbnail = (props) => { ImageThumbnail.propTypes = { image: imageObject.isRequired, shouldLazyLoad: PropTypes.bool.isRequired, - thumbnailsContainerRef: elementRef.isRequired + thumbnailsContainerRef: elementRef.isRequired, + fallbackImg: PropTypes.string }; diff --git a/src/components/Slide/Slide.js b/src/components/Slide/Slide.js index 9ff3ef2..69b683d 100644 --- a/src/components/Slide/Slide.js +++ b/src/components/Slide/Slide.js @@ -19,6 +19,7 @@ export const Slide = (props) => { widgetsHasShadow={props.widgetsHasShadow} hasCaption={props.hasCaption} slidesContainerRef={props.slidesContainerRef} + fallbackImg={props.fallbackImg} /> ) : ( @@ -44,5 +45,6 @@ Slide.propTypes = { hasCaption: largeWidgetPositions.isRequired, slidesContainerRef: elementRef.isRequired, reference: elementRef, - isCurrent: PropTypes.bool.isRequired + isCurrent: PropTypes.bool.isRequired, + fallbackImg: PropTypes.string }; diff --git a/src/components/Slides/Slides.js b/src/components/Slides/Slides.js index c56c051..8eab763 100644 --- a/src/components/Slides/Slides.js +++ b/src/components/Slides/Slides.js @@ -38,6 +38,7 @@ export const Slides = (props) => { widgetsHasShadow={props.widgetsHasShadow} hasCaption={props.hasCaptions} isCurrent={index === props.curIndex} + fallbackImg={props.fallbackImg} /> ); })} @@ -58,5 +59,6 @@ Slides.propTypes = { objectFit: objectFitStyles.isRequired, widgetsHasShadow: PropTypes.bool.isRequired, hasCaptions: largeWidgetPositions.isRequired, - curIndex: PropTypes.number + curIndex: PropTypes.number, + fallbackImg: PropTypes.string }; diff --git a/src/components/Thumbnail/Thumbnail.js b/src/components/Thumbnail/Thumbnail.js index 7daeda5..1b77ab4 100644 --- a/src/components/Thumbnail/Thumbnail.js +++ b/src/components/Thumbnail/Thumbnail.js @@ -15,6 +15,7 @@ export const Thumbnail = (props) => { thumbnailsContainerRef={props.thumbnailsContainerRef} image={props.slide} shouldLazyLoad={props.shouldLazyLoad} + fallbackImg={props.fallbackImg} /> ) : ( @@ -63,5 +64,6 @@ Thumbnail.propTypes = { isCurrent: PropTypes.bool.isRequired, width: PropTypes.string, reference: elementRef.isRequired, - onClick: PropTypes.func.isRequired + onClick: PropTypes.func.isRequired, + fallbackImg: PropTypes.string }; diff --git a/src/components/Thumbnails/Thumbnails.js b/src/components/Thumbnails/Thumbnails.js index 5d415ca..3a6450a 100644 --- a/src/components/Thumbnails/Thumbnails.js +++ b/src/components/Thumbnails/Thumbnails.js @@ -43,6 +43,7 @@ export const Thumbnails = (props) => { isCurrent={Number(key) === props.curIndex} width={props.width} onClick={callbacks[key]} + fallbackImg={props.fallbackImg} /> ); })} @@ -61,7 +62,8 @@ Thumbnails.propTypes = { thumbnails: PropTypes.array.isRequired, hasImages: PropTypes.bool.isRequired, shouldLazyLoad: PropTypes.bool.isRequired, - curIndex: PropTypes.number.isRequired + curIndex: PropTypes.number.isRequired, + fallbackImg: PropTypes.string }; Thumbnails.defaultProps = {