@lambda-capacitor/react-image-appear
Version:
ReactJS component to make images appear with transition as they load.
208 lines (182 loc) • 4.94 kB
JavaScript
/*
react-image-appear v1.2.22
Copyright (c) 2018 Arun Michael Dsouza (amdsouza92@gmail.com)
Licence: MIT
*/
import React, { Component } from "react";
import PropTypes from "prop-types";
import {
LOADER,
LOADER_STYLE,
PLACEHOLDER,
PLACEHOLDER_STYLE,
ANIMATION,
ANIMATION_DURATION,
EASING
} from "./constants";
import { injectAnimationsScript } from "./helpers";
injectAnimationsScript();
class ReactImageAppear extends Component {
constructor(props) {
super(props);
this.state = {
imgComponent: null
};
this.imageOnLoad = this.imageOnLoad.bind(this);
this.getImageDimensions = this.getImageDimensions.bind(this);
this.parseComputedDimensions = this.parseComputedDimensions.bind(this);
this.createPlaceholder = this.createPlaceholder.bind(this);
this.getPlaceholderStyle = this.getPlaceholderStyle.bind(this);
this.createLoader = this.createLoader.bind(this);
this.getLoaderStyle = this.getLoaderStyle.bind(this);
}
componentDidMount() {
const { src, className } = this.props;
let imgElement;
this.setState(
(prevState, props) => {
return {
imgComponent: React.createElement("img", {
src,
onLoad: this.imageOnLoad,
style: {
opacity: 0,
position: "absolute"
},
className,
ref: ref => {
imgElement = ref;
}
})
};
},
() => {
this.getImageDimensions(imgElement);
}
);
}
imageOnLoad() {
const {
src,
animation,
animationDuration,
easing,
className,
onClick
} = this.props;
this.setState((prevState, props) => {
return {
imgComponent: React.createElement("img", {
src,
style: {
animation: `${animation} ${animationDuration} ${easing}`,
position: "absolute"
},
className,
onClick: onClick
})
};
});
}
getImageDimensions(imgElement) {
const that = this,
dimensionsInterval = setInterval(() => {
const { width, height } = this.parseComputedDimensions(imgElement);
if (width && height) {
clearInterval(dimensionsInterval);
that.createPlaceholder(width, height);
}
}, 10);
}
parseComputedDimensions(el) {
return {
width: Number(window.getComputedStyle(el).width.match(/\d+/)),
height: Number(window.getComputedStyle(el).height.match(/\d+/))
};
}
createPlaceholder(width, height) {
const { imgComponent } = this.state,
{ placeholderClass } = this.props;
const placeholder = React.createElement(
"div",
{
style: this.getPlaceholderStyle(width, height),
className: placeholderClass
},
React.cloneElement(imgComponent),
this.createLoader()
);
this.setState((prevState, props) => {
return {
imgComponent: placeholder
};
});
}
getPlaceholderStyle(width, height) {
const { placeholderStyle, placeholder } = this.props;
let placeholderStyling = Object.assign(
{},
PLACEHOLDER_STYLE,
placeholderStyle
);
switch (typeof placeholder) {
case "boolean":
if (placeholder) {
placeholderStyling = Object.assign({}, placeholderStyling, {
backgroundImage: `url(${PLACEHOLDER})`
});
}
break;
case "string":
placeholderStyling = Object.assign({}, placeholderStyling, {
backgroundImage: `url(${placeholder})`
});
break;
}
return Object.assign({}, placeholderStyling, { width, height });
}
createLoader() {
const { loader, loaderClass, showLoader } = this.props;
return null;
}
getLoaderStyle() {
const { loaderStyle } = this.props;
return Object.assign({}, LOADER_STYLE, loaderStyle);
}
render() {
const { imgComponent } = this.state;
return imgComponent;
}
}
ReactImageAppear.propTypes = {
src: PropTypes.string.isRequired,
loader: PropTypes.string,
loaderStyle: PropTypes.object,
loaderClass: PropTypes.string,
placeholder: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
placeholderStyle: PropTypes.object,
placeholderClass: PropTypes.string,
animation: PropTypes.string,
animationDuration: PropTypes.string,
easing: PropTypes.string,
showLoader: PropTypes.bool,
className: PropTypes.string,
onClick: PropTypes.func
};
ReactImageAppear.defaultProps = {
loader: LOADER,
loaderStyle: {},
loaderClass: "",
placeholder: false,
placeholderStyle: {},
placeholderClass: "",
animation: ANIMATION,
animationDuration: ANIMATION_DURATION,
easing: EASING,
showLoader: true,
className: "",
onClick: () => {
console.log("image clicked");
}
};
export default ReactImageAppear;