UNPKG

gatsby-background-image

Version:

Lazy-loading React background-image component with optional support for the blur-up effect.

377 lines (317 loc) 13.3 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.default = void 0; var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose")); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _inheritsLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/inheritsLoose")); var _react = _interopRequireDefault(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _BackgroundUtils = _interopRequireDefault(require("./lib/BackgroundUtils")); var _HelperUtils = require("./lib/HelperUtils"); var _ImageUtils = require("./lib/ImageUtils"); var _ImageCache = require("./lib/ImageCache"); var _ImageRef = require("./lib/ImageRef"); var _ImageHandling = require("./lib/ImageHandling"); var _StyleUtils = require("./lib/StyleUtils"); var _StyleCreation = require("./lib/StyleCreation"); var _IntersectionObserverUtils = require("./lib/IntersectionObserverUtils"); var _SimpleUtils = require("./lib/SimpleUtils"); var _excluded = ["className", "style", "fluid", "fixed", "backgroundColor", "durationFadeIn", "Tag", "children", "keepStatic"]; var BackgroundImage = function (_React$Component) { (0, _inheritsLoose2.default)(BackgroundImage, _React$Component); function BackgroundImage(props) { var _this; _this = _React$Component.call(this, props) || this; _this.intersectionListener = function () { var imageInCache = (0, _ImageCache.inImageCache)(_this.props); if (!_this.state.isVisible && typeof _this.props.onStartLoad === "function") { _this.props.onStartLoad({ wasCached: imageInCache }); } _this.imageRef = (0, _ImageRef.activatePictureRef)(_this.imageRef, _this.props, _this.selfRef); _this.setState(function (state) { return { isVisible: true, imageState: state.imageState + 1 }; }, function () { _this.setState(function (state) { return { imgLoaded: imageInCache, imgCached: (0, _ImageRef.hasActivatedPictureRefs)(_this.imageRef), imageState: state.imageState + 1 }; }); }); }; var convertedProps = (0, _HelperUtils.convertProps)(props); var isVisible = true; var imgLoaded = false; var IOSupported = false; var fadeIn = convertedProps.fadeIn; var seenBefore = (0, _ImageCache.inImageCache)(convertedProps); if (!seenBefore && (0, _SimpleUtils.isBrowser)() && window.IntersectionObserver) { isVisible = false; IOSupported = true; } if (!(0, _SimpleUtils.isBrowser)()) { isVisible = false; } if (convertedProps.critical) { isVisible = true; IOSupported = false; } var hasNoScript = !(convertedProps.critical && !fadeIn) && !(0, _SimpleUtils.isBrowser)(); var imageState = 0; var _fixClassName = (0, _StyleUtils.fixClassName)(convertedProps), currentClassNames = _fixClassName[0]; _this.backgroundStyles = (0, _StyleUtils.presetBackgroundStyles)((0, _BackgroundUtils.default)(convertedProps.className)); _this.handleImageLoaded = _this.handleImageLoaded.bind((0, _assertThisInitialized2.default)(_this)); _this.handleRef = _this.handleRef.bind((0, _assertThisInitialized2.default)(_this)); _this.imageRef = (0, _ImageRef.createPictureRef)((0, _extends2.default)({}, convertedProps, { isVisible: isVisible }), _this.handleImageLoaded); _this.selfRef = null; _this.state = { isVisible: isVisible, imgLoaded: imgLoaded, IOSupported: IOSupported, fadeIn: fadeIn, hasNoScript: hasNoScript, seenBefore: seenBefore, imageState: imageState, currentClassNames: currentClassNames }; return _this; } var _proto = BackgroundImage.prototype; _proto.componentDidMount = function componentDidMount() { this.backgroundStyles = (0, _StyleUtils.presetBackgroundStyles)((0, _BackgroundUtils.default)(this.props.className)); if (this.state.isVisible && typeof this.props.onStartLoad === "function") { this.props.onStartLoad({ wasCached: (0, _ImageCache.inImageCache)(this.props) }); } if (this.props.critical || this.state.seenBefore) { if ((0, _ImageRef.imageReferenceCompleted)(this.imageRef, this.props)) { this.handleImageLoaded(); } } var _fixClassName2 = (0, _StyleUtils.fixClassName)(this.props), currentClassNames = _fixClassName2[0]; this.setState({ currentClassNames: currentClassNames }); }; _proto.componentDidUpdate = function componentDidUpdate(prevProps) { var _this2 = this; if ((0, _ImageUtils.imagePropsChanged)(this.props, prevProps)) { var convertedProps = (0, _HelperUtils.convertProps)(this.props); var imageInCache = (0, _ImageCache.inImageCache)(convertedProps); var _fixClassName3 = (0, _StyleUtils.fixClassName)(convertedProps), currentClassNames = _fixClassName3[0]; this.setState({ isVisible: imageInCache || convertedProps.critical, imgLoaded: imageInCache, seenBefore: imageInCache, currentClassNames: currentClassNames }, function () { _this2.bgImage = (0, _ImageUtils.getCurrentFromData)({ data: _this2.imageRef, propName: "currentSrc", returnArray: true }) || (0, _ImageUtils.getCurrentFromData)({ data: _this2.imageRef, propName: "src", returnArray: true }); _this2.imageRef = (0, _ImageRef.createPictureRef)((0, _extends2.default)({}, convertedProps, { isVisible: _this2.state.isVisible }), _this2.handleImageLoaded); }); } }; _proto.componentWillUnmount = function componentWillUnmount() { if (this.imageRef) { if (Array.isArray(this.imageRef)) { this.imageRef.forEach(function (currentImageRef) { if (!!currentImageRef && !(0, _SimpleUtils.isString)(currentImageRef)) { currentImageRef.onload = null; } }); } else { this.imageRef.onload = null; } } if (this.cleanUpListeners) { this.cleanUpListeners(); } }; _proto.handleRef = function handleRef(ref) { this.selfRef = ref; if (this.state.IOSupported && ref) { this.cleanUpListeners = (0, _IntersectionObserverUtils.listenToIntersections)(ref, this.intersectionListener, this.props.rootMargin); } }; _proto.handleImageLoaded = function handleImageLoaded() { (0, _ImageCache.activateCacheForImage)(this.props); this.setState(function (state) { return { imgLoaded: true, imageState: state.imageState + 1 }; }); if (this.state.seenBefore) { this.setState({ fadeIn: false }); } if (this.props.onLoad) { this.props.onLoad(); } }; _proto.render = function render() { var _fixOpacity = (0, _StyleUtils.fixOpacity)((0, _HelperUtils.convertProps)(this.props), this.props.preserveStackingContext), className = _fixOpacity.className, _fixOpacity$style = _fixOpacity.style, style = _fixOpacity$style === void 0 ? {} : _fixOpacity$style, fluid = _fixOpacity.fluid, fixed = _fixOpacity.fixed, backgroundColor = _fixOpacity.backgroundColor, durationFadeIn = _fixOpacity.durationFadeIn, Tag = _fixOpacity.Tag, children = _fixOpacity.children, keepStatic = _fixOpacity.keepStatic, props = (0, _objectWithoutPropertiesLoose2.default)(_fixOpacity, _excluded); var remainingProps = (0, _HelperUtils.stripRemainingProps)(props); var bgColor = typeof backgroundColor === "boolean" ? "lightgray" : typeof backgroundColor !== "undefined" ? backgroundColor : ""; var shouldFadeIn = this.state.fadeIn === true && !this.state.imgCached || this.props.fadeIn === "soft"; var transitionDelay = shouldFadeIn ? durationFadeIn / 2 + "ms" : "none"; var divStyle = (0, _extends2.default)({ position: "relative" }, style); if (!this.props.preserveStackingContext) divStyle.opacity = 0.99; var image = (0, _ImageUtils.getCurrentSrcData)({ fluid: fluid, fixed: fixed, returnArray: true }); var noScriptImageData = (0, _ImageUtils.getCurrentSrcData)({ fluid: fluid, fixed: fixed }) || {}; if (fluid || fixed) { if (fixed) { divStyle.width = style.width || image.width; divStyle.height = style.height || image.height; divStyle.display = "inline-block"; if (style.display === "inherit") { delete divStyle.display; } } } else if (keepStatic) { noScriptImageData.srcSet = ''; } else { return null; } var newImageSettings = (0, _ImageHandling.switchImageSettings)({ image: image, bgImage: this.bgImage, imageRef: this.imageRef, state: this.state }); this.bgImage = newImageSettings.nextImageArray || newImageSettings.nextImage || this.bgImage; var pseudoStyles = (0, _StyleCreation.createPseudoStyles)((0, _extends2.default)({ className: this.state.currentClassNames, transitionDelay: transitionDelay, bgColor: bgColor, backgroundStyles: this.backgroundStyles, style: style, fadeIn: shouldFadeIn }, newImageSettings, { originalData: fluid || fixed })); var noScriptPseudoStyles = (0, _StyleCreation.createNoScriptStyles)({ image: image, bgColor: bgColor, className: this.state.currentClassNames, backgroundStyles: this.backgroundStyles, style: style }); var componentKey = "" + (fluid ? "fluid" : "") + (fixed ? "fixed" : "") + "-" + JSON.stringify(noScriptImageData.srcSet); var currentStyles = (0, _extends2.default)({}, this.backgroundStyles, divStyle); return _react.default.createElement(Tag, (0, _extends2.default)({ className: this.state.currentClassNames, style: currentStyles, ref: this.handleRef, key: componentKey }, remainingProps), _react.default.createElement("style", { dangerouslySetInnerHTML: { __html: pseudoStyles } }), this.state.hasNoScript && _react.default.createElement("noscript", null, _react.default.createElement("style", { dangerouslySetInnerHTML: { __html: noScriptPseudoStyles } })), children); }; return BackgroundImage; }(_react.default.Component); BackgroundImage.defaultProps = { critical: false, fadeIn: true, durationFadeIn: 500, Tag: "div", preserveStackingContext: false, rootMargin: "200px", keepStatic: false }; 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, srcAvif: _propTypes.default.string, srcSetAvif: _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, base64: _propTypes.default.string, tracedSVG: _propTypes.default.string, srcWebp: _propTypes.default.string, srcSetWebp: _propTypes.default.string, srcAvif: _propTypes.default.string, srcSetAvif: _propTypes.default.string, media: _propTypes.default.string }); BackgroundImage.propTypes = { fixed: _propTypes.default.oneOfType([fixedObject, _propTypes.default.arrayOf(fixedObject), _propTypes.default.arrayOf(_propTypes.default.oneOfType([fixedObject, _propTypes.default.string]))]), fluid: _propTypes.default.oneOfType([fluidObject, _propTypes.default.arrayOf(fluidObject), _propTypes.default.arrayOf(_propTypes.default.oneOfType([fluidObject, _propTypes.default.string]))]), fadeIn: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]), durationFadeIn: _propTypes.default.number, className: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.object]), critical: _propTypes.default.bool, crossOrigin: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]), style: _propTypes.default.oneOfType([_propTypes.default.object, _propTypes.default.array]), 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.oneOfType([_propTypes.default.string, _propTypes.default.func]), preserveStackingContext: _propTypes.default.bool, rootMargin: _propTypes.default.string, keepStatic: _propTypes.default.bool }; var _default = BackgroundImage; exports.default = _default;