"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.default = void 0; var _inheritsLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/inheritsLoose")); var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose")); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _react = _interopRequireDefault(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var logDeprecationNotice = function logDeprecationNotice(prop, replacement) { if (process.env.NODE_ENV === "production") { return; } console.log("\n The \"" + prop + "\" prop is now deprecated and will be removed in the next major version\n of \"gatsby-image\".\n "); if (replacement) { console.log("Please use " + replacement + " instead of \"" + prop + "\"."); } }; // Handle legacy props during their deprecation phase var convertProps = function convertProps(props) { var convertedProps = (0, _extends2.default)({}, props); var resolutions = convertedProps.resolutions, sizes = convertedProps.sizes, critical = convertedProps.critical; if (resolutions) { convertedProps.fixed = resolutions; delete convertedProps.resolutions; } if (sizes) { convertedProps.fluid = sizes; delete convertedProps.sizes; } if (critical) { logDeprecationNotice("critical", "the native \"loading\" attribute"); convertedProps.loading = "eager"; } // convert fluid & fixed to arrays so we only have to work with arrays if (convertedProps.fluid) { convertedProps.fluid = groupByMedia([].concat(convertedProps.fluid)); } if (convertedProps.fixed) { convertedProps.fixed = groupByMedia([].concat(convertedProps.fixed)); } return convertedProps; }; /** * Find the source of an image to use as a key in the image cache. * Use `the first image in either `fixed` or `fluid` * @param {{fluid: {src: string}[], fixed: {src: string}[]}} args * @return {string} */ var getImageSrcKey = function getImageSrcKey(_ref) { var fluid = _ref.fluid, fixed = _ref.fixed; var data = fluid && fluid[0] || fixed && fixed[0]; return data.src; }; // Cache if we've seen an image before so we don't bother with // lazy-loading & fading in on subsequent mounts. var imageCache = Object.create({}); var inImageCache = function inImageCache(props) { var convertedProps = convertProps(props); // Find src var src = getImageSrcKey(convertedProps); return imageCache[src] || false; }; var activateCacheForImage = function activateCacheForImage(props) { var convertedProps = convertProps(props); // Find src var src = getImageSrcKey(convertedProps); imageCache[src] = true; }; // Native lazy-loading support: https://addyosmani.com/blog/lazy-loading/ var hasNativeLazyLoadSupport = typeof HTMLImageElement !== "undefined" && "loading" in HTMLImageElement.prototype; var isBrowser = typeof window !== "undefined"; var hasIOSupport = isBrowser && window.IntersectionObserver; var io; var listeners = new WeakMap(); function getIO() { if (typeof io === "undefined" && typeof window !== "undefined" && window.IntersectionObserver) { io = new window.IntersectionObserver(function (entries) { entries.forEach(function (entry) { if (listeners.has(entry.target)) { var cb = listeners.get(entry.target); // Edge doesn't currently support isIntersecting, so also test for an intersectionRatio > 0 if (entry.isIntersecting || entry.intersectionRatio > 0) { io.unobserve(entry.target); listeners.delete(entry.target); cb(); } } }); }, { rootMargin: "200px" }); } return io; } function generateImageSources(imageVariants) { return imageVariants.map(function (_ref2) { var src = _ref2.src, srcSet = _ref2.srcSet, srcSetWebp = _ref2.srcSetWebp, media = _ref2.media, sizes = _ref2.sizes; return _react.default.createElement(_react.default.Fragment, { key: src }, srcSetWebp && _react.default.createElement("source", { type: "image/webp", media: media, srcSet: srcSetWebp, sizes: sizes }), _react.default.createElement("source", { media: media, srcSet: srcSet, sizes: sizes })); }); } // Return an array ordered by elements having a media prop, does not use // native sort, as a stable sort is not guaranteed by all browsers/versions function groupByMedia(imageVariants) { var withMedia = []; var without = []; imageVariants.forEach(function (variant) { return (variant.media ? withMedia : without).push(variant); }); if (without.length > 1 && process.env.NODE_ENV !== "production") { console.warn("We've found " + without.length + " sources without a media property. They might be ignored by the browser, see: https://www.gatsbyjs.org/packages/gatsby-image/#art-directing-multiple-images"); } return withMedia.concat(without); } function generateTracedSVGSources(imageVariants) { return imageVariants.map(function (_ref3) { var src = _ref3.src, media = _ref3.media, tracedSVG = _ref3.tracedSVG; return _react.default.createElement("source", { key: src, media: media, srcSet: tracedSVG }); }); } function generateBase64Sources(imageVariants) { return imageVariants.map(function (_ref4) { var src = _ref4.src, media = _ref4.media, base64 = _ref4.base64; return _react.default.createElement("source", { key: src, media: media, srcSet: base64 }); }); } function generateNoscriptSource(_ref5, isWebp) { var srcSet = _ref5.srcSet, srcSetWebp = _ref5.srcSetWebp, media = _ref5.media, sizes = _ref5.sizes; var src = isWebp ? srcSetWebp : srcSet; var mediaAttr = media ? "media=\"" + media + "\" " : ""; var typeAttr = isWebp ? "type='image/webp' " : ""; var sizesAttr = sizes ? "sizes=\"" + sizes + "\" " : ""; return ""; } function generateNoscriptSources(imageVariants) { return imageVariants.map(function (variant) { return (variant.srcSetWebp ? generateNoscriptSource(variant, true) : "") + generateNoscriptSource(variant); }).join(""); } var listenToIntersections = function listenToIntersections(el, cb) { var observer = getIO(); if (observer) { observer.observe(el); listeners.set(el, cb); } return function () { observer.unobserve(el); listeners.delete(el); }; }; var noscriptImg = function noscriptImg(props) { // Check if prop exists before adding each attribute to the string output below to prevent // HTML validation issues caused by empty values like width="" and height="" var src = props.src ? "src=\"" + props.src + "\" " : "src=\"\" "; // required attribute var sizes = props.sizes ? "sizes=\"" + props.sizes + "\" " : ""; var srcSet = props.srcSet ? "srcset=\"" + props.srcSet + "\" " : ""; var title = props.title ? "title=\"" + props.title + "\" " : ""; var alt = props.alt ? "alt=\"" + props.alt + "\" " : "alt=\"\" "; // required attribute var width = props.width ? "width=\"" + props.width + "\" " : ""; var height = props.height ? "height=\"" + props.height + "\" " : ""; var crossOrigin = props.crossOrigin ? "crossorigin=\"" + props.crossOrigin + "\" " : ""; var loading = props.loading ? "loading=\"" + props.loading + "\" " : ""; var draggable = props.draggable ? "draggable=\"" + props.draggable + "\" " : ""; var sources = generateNoscriptSources(props.imageVariants); return "" + sources + ""; }; // Earlier versions of gatsby-image during the 2.x cycle did not wrap // the `Img` component in a `picture` element. This maintains compatibility // until a breaking change can be introduced in the next major release var Placeholder = function Placeholder(_ref6) { var src = _ref6.src, imageVariants = _ref6.imageVariants, generateSources = _ref6.generateSources, spreadProps = _ref6.spreadProps; var baseImage = _react.default.createElement(Img, (0, _extends2.default)({ src: src }, spreadProps)); return imageVariants.length > 1 ? _react.default.createElement("picture", null, generateSources(imageVariants), baseImage) : baseImage; }; var Img = _react.default.forwardRef(function (props, ref) { var sizes = props.sizes, srcSet = props.srcSet, src = props.src, style = props.style, onLoad = props.onLoad, onError = props.onError, loading = props.loading, draggable = props.draggable, otherProps = (0, _objectWithoutPropertiesLoose2.default)(props, ["sizes", "srcSet", "src", "style", "onLoad", "onError", "loading", "draggable"]); return _react.default.createElement("img", (0, _extends2.default)({ sizes: sizes, srcSet: srcSet, src: src }, otherProps, { onLoad: onLoad, onError: onError, ref: ref, loading: loading, draggable: draggable, style: (0, _extends2.default)({ position: "absolute", top: 0, left: 0, width: "100%", height: "100%", objectFit: "cover", objectPosition: "center" }, style) })); }); Img.propTypes = { style: _propTypes.default.object, onError: _propTypes.default.func, onLoad: _propTypes.default.func }; var Image = /*#__PURE__*/ function (_React$Component) { (0, _inheritsLoose2.default)(Image, _React$Component); function Image(props) { var _this; _this = _React$Component.call(this, props) || this; // If this image has already been loaded before then we can assume it's // already in the browser cache so it's cheap to just show directly. _this.seenBefore = isBrowser && inImageCache(props); _this.addNoScript = !(props.critical && !props.fadeIn); _this.useIOSupport = !hasNativeLazyLoadSupport && hasIOSupport && !props.critical && !_this.seenBefore; var isVisible = props.critical || props.loading == "eager" || isBrowser && (hasNativeLazyLoadSupport || !_this.useIOSupport); _this.state = { isVisible: isVisible, imgLoaded: false, imgCached: false, fadeIn: !_this.seenBefore && props.fadeIn }; _this.imageRef = _react.default.createRef(); _this.handleImageLoaded = _this.handleImageLoaded.bind((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this))); _this.handleRef = _this.handleRef.bind((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this))); return _this; } var _proto = Image.prototype; _proto.componentDidMount = function componentDidMount() { if (this.state.isVisible && typeof this.props.onStartLoad === "function") { this.props.onStartLoad({ wasCached: inImageCache(this.props) }); } if (this.props.critical) { var img = this.imageRef.current; if (img && img.complete) { this.handleImageLoaded(); } } }; _proto.componentWillUnmount = function componentWillUnmount() { if (this.cleanUpListeners) { this.cleanUpListeners(); } }; // Specific to IntersectionObserver based lazy-load support _proto.handleRef = function handleRef(ref) { var _this2 = this; if (this.useIOSupport && ref) { this.cleanUpListeners = listenToIntersections(ref, function () { var imageInCache = inImageCache(_this2.props); if (!_this2.state.isVisible && typeof _this2.props.onStartLoad === "function") { _this2.props.onStartLoad({ wasCached: imageInCache }); } // imgCached and imgLoaded must update after isVisible, // Once isVisible is true, imageRef becomes accessible, which imgCached needs access to. // imgLoaded and imgCached are in a 2nd setState call to be changed together, // avoiding initiating unnecessary animation frames from style changes. _this2.setState({ isVisible: true }, function () { return _this2.setState({ imgLoaded: imageInCache, // `currentSrc` should be a string, but can be `undefined` in IE, // !! operator validates the value is not undefined/null/"" imgCached: !!_this2.imageRef.current.currentSrc }); }); }); } }; _proto.handleImageLoaded = function handleImageLoaded() { activateCacheForImage(this.props); this.setState({ imgLoaded: true }); if (this.props.onLoad) { this.props.onLoad(); } }; _proto.render = function render() { var _convertProps = convertProps(this.props), title = _convertProps.title, alt = _convertProps.alt, className = _convertProps.className, _convertProps$style = _convertProps.style, style = _convertProps$style === void 0 ? {} : _convertProps$style, _convertProps$imgStyl = _convertProps.imgStyle, imgStyle = _convertProps$imgStyl === void 0 ? {} : _convertProps$imgStyl, _convertProps$placeho = _convertProps.placeholderStyle, placeholderStyle = _convertProps$placeho === void 0 ? {} : _convertProps$placeho, placeholderClassName = _convertProps.placeholderClassName, fluid = _convertProps.fluid, fixed = _convertProps.fixed, backgroundColor = _convertProps.backgroundColor, durationFadeIn = _convertProps.durationFadeIn, Tag = _convertProps.Tag, itemProp = _convertProps.itemProp, loading = _convertProps.loading, draggable = _convertProps.draggable; var shouldReveal = this.state.fadeIn === false || this.state.imgLoaded; var shouldFadeIn = this.state.fadeIn === true && !this.state.imgCached; var imageStyle = (0, _extends2.default)({ opacity: shouldReveal ? 1 : 0, transition: shouldFadeIn ? "opacity " + durationFadeIn + "ms" : "none" }, imgStyle); var bgColor = typeof backgroundColor === "boolean" ? "lightgray" : backgroundColor; var delayHideStyle = { transitionDelay: durationFadeIn + "ms" }; var imagePlaceholderStyle = (0, _extends2.default)({ opacity: this.state.imgLoaded ? 0 : 1 }, shouldFadeIn && delayHideStyle, imgStyle, placeholderStyle); var placeholderImageProps = { title: title, alt: !this.state.isVisible ? alt : "", style: imagePlaceholderStyle, className: placeholderClassName }; if (fluid) { var imageVariants = fluid; var image = imageVariants[0]; return _react.default.createElement(Tag, { className: (className ? className : "") + " gatsby-image-wrapper", style: (0, _extends2.default)({ position: "relative", overflow: "hidden" }, style), ref: this.handleRef, key: "fluid-" + JSON.stringify(image.srcSet) }, _react.default.createElement(Tag, { style: { width: "100%", paddingBottom: 100 / image.aspectRatio + "%" } }), bgColor && _react.default.createElement(Tag, { title: title, style: (0, _extends2.default)({ backgroundColor: bgColor, position: "absolute", top: 0, bottom: 0, opacity: !this.state.imgLoaded ? 1 : 0, right: 0, left: 0 }, shouldFadeIn && delayHideStyle) }), image.base64 && _react.default.createElement(Placeholder, { src: image.base64, spreadProps: placeholderImageProps, imageVariants: imageVariants, generateSources: generateBase64Sources }), image.tracedSVG && _react.default.createElement(Placeholder, { src: image.tracedSVG, spreadProps: placeholderImageProps, imageVariants: imageVariants, generateSources: generateTracedSVGSources }), this.state.isVisible && _react.default.createElement("picture", null, generateImageSources(imageVariants), _react.default.createElement(Img, { alt: alt, title: title, sizes: image.sizes, src: image.src, crossOrigin: this.props.crossOrigin, srcSet: image.srcSet, style: imageStyle, ref: this.imageRef, onLoad: this.handleImageLoaded, onError: this.props.onError, itemProp: itemProp, loading: loading, draggable: draggable })), this.addNoScript && _react.default.createElement("noscript", { dangerouslySetInnerHTML: { __html: noscriptImg((0, _extends2.default)({ alt: alt, title: title, loading: loading }, image, { imageVariants: imageVariants })) } })); } if (fixed) { var _imageVariants = fixed; var _image = _imageVariants[0]; var divStyle = (0, _extends2.default)({ position: "relative", overflow: "hidden", display: "inline-block", width: _image.width, height: _image.height }, style); if (style.display === "inherit") { delete divStyle.display; } return _react.default.createElement(Tag, { className: (className ? className : "") + " gatsby-image-wrapper", style: divStyle, ref: this.handleRef, key: "fixed-" + JSON.stringify(_image.srcSet) }, bgColor && _react.default.createElement(Tag, { title: title, style: (0, _extends2.default)({ backgroundColor: bgColor, width: _image.width, opacity: !this.state.imgLoaded ? 1 : 0, height: _image.height }, shouldFadeIn && delayHideStyle) }), _image.base64 && _react.default.createElement(Placeholder, { src: _image.base64, spreadProps: placeholderImageProps, imageVariants: _imageVariants, generateSources: generateBase64Sources }), _image.tracedSVG && _react.default.createElement(Placeholder, { src: _image.tracedSVG, spreadProps: placeholderImageProps, imageVariants: _imageVariants, generateSources: generateTracedSVGSources }), this.state.isVisible && _react.default.createElement("picture", null, generateImageSources(_imageVariants), _react.default.createElement(Img, { alt: alt, title: title, width: _image.width, height: _image.height, sizes: _image.sizes, src: _image.src, crossOrigin: this.props.crossOrigin, srcSet: _image.srcSet, style: imageStyle, ref: this.imageRef, onLoad: this.handleImageLoaded, onError: this.props.onError, itemProp: itemProp, loading: loading, draggable: draggable })), this.addNoScript && _react.default.createElement("noscript", { dangerouslySetInnerHTML: { __html: noscriptImg((0, _extends2.default)({ alt: alt, title: title, loading: loading }, _image, { imageVariants: _imageVariants })) } })); } return null; }; return Image; }(_react.default.Component); Image.defaultProps = { fadeIn: true, durationFadeIn: 500, alt: "", Tag: "div", // We set it to `lazy` by default because it's best to default to a performant // setting and let the user "opt out" to `eager` loading: "lazy" }; var fixedObject = _propTypes.default.shape({ width: _propTypes.default.number.isRequired, height: _propTypes.default.number.isRequired, src: _propTypes.default.string.isRequired, srcSet: _propTypes.default.string.isRequired, base64: _propTypes.default.string, tracedSVG: _propTypes.default.string, srcWebp: _propTypes.default.string, srcSetWebp: _propTypes.default.string, media: _propTypes.default.string }); var fluidObject = _propTypes.default.shape({ aspectRatio: _propTypes.default.number.isRequired, src: _propTypes.default.string.isRequired, srcSet: _propTypes.default.string.isRequired, sizes: _propTypes.default.string.isRequired, base64: _propTypes.default.string, tracedSVG: _propTypes.default.string, srcWebp: _propTypes.default.string, srcSetWebp: _propTypes.default.string, media: _propTypes.default.string }); Image.propTypes = { resolutions: fixedObject, sizes: fluidObject, fixed: _propTypes.default.oneOfType([fixedObject, _propTypes.default.arrayOf(fixedObject)]), fluid: _propTypes.default.oneOfType([fluidObject, _propTypes.default.arrayOf(fluidObject)]), fadeIn: _propTypes.default.bool, durationFadeIn: _propTypes.default.number, title: _propTypes.default.string, alt: _propTypes.default.string, className: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.object]), // Support Glamor's css prop. critical: _propTypes.default.bool, crossOrigin: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]), style: _propTypes.default.object, imgStyle: _propTypes.default.object, placeholderStyle: _propTypes.default.object, placeholderClassName: _propTypes.default.string, backgroundColor: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]), onLoad: _propTypes.default.func, onError: _propTypes.default.func, onStartLoad: _propTypes.default.func, Tag: _propTypes.default.string, itemProp: _propTypes.default.string, loading: _propTypes.default.oneOf(["auto", "lazy", "eager"]), draggable: _propTypes.default.bool }; var _default = Image; exports.default = _default;