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
JavaScript
"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;