UNPKG

@nbamford123/arwes

Version:

Futuristic Sci-Fi and Cyberpunk Graphical User Interface Framework for Web Apps

208 lines (180 loc) 5.13 kB
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; import AnimationComponent from '../Animation'; import FrameComponent from '../Frame'; import LoadingComponent from '../Loading'; import { getResponsiveResource } from '../tools/utils'; import createLoaderModule from '../tools/createLoader'; import createResponsiveModule from '../tools/createResponsive'; export default class Image extends Component { static propTypes = { Animation: PropTypes.any.isRequired, Frame: PropTypes.any.isRequired, Loading: PropTypes.any.isRequired, createLoader: PropTypes.any.isRequired, createResponsive: PropTypes.any.isRequired, theme: PropTypes.any.isRequired, classes: PropTypes.any.isRequired, animate: PropTypes.bool, show: PropTypes.bool, animation: PropTypes.object, layer: PropTypes.oneOf(['primary', 'secondary', 'header', 'control', 'success', 'alert', 'disabled']), /** * If the resources should be loaded. */ loadResources: PropTypes.bool, /** * The image resource or the images resources according to device viewport. */ resources: PropTypes.oneOfType([ PropTypes.string, PropTypes.shape({ small: PropTypes.string.isRequired, medium: PropTypes.string.isRequired, large: PropTypes.string.isRequired, xlarge: PropTypes.string.isRequired, }) ]).isRequired, /** * i18n messages. */ i18n: PropTypes.shape({ error: PropTypes.string, }), /** * Props to pass down to the `<img />` element. */ imgProps: PropTypes.object, /** * If function, receives the animation status object. */ children: PropTypes.any, } static defaultProps = { Animation: AnimationComponent, Frame: FrameComponent, Loading: LoadingComponent, createLoader: createLoaderModule, createResponsive: createResponsiveModule, show: true, layer: 'primary', loadResources: true, i18n: { error: 'Image error', }, imgProps: {}, } getDefaultState () { return { ready: false, // if active resource is loaded error: false, // if resource had an error resource: null, // the active resource }; } constructor () { super(...arguments); this.state = this.getDefaultState(); this.loader = this.props.createLoader(); this.responsive = this.props.createResponsive({ getTheme: () => this.props.theme }); } componentDidMount () { this.loadResource(); } componentDidUpdate (prevProps) { if (this.props.resources !== prevProps.resources) { this.loadResource(); } } render () { const { Animation, Frame, Loading, createLoader, createResponsive, animation, theme, classes, animate, show, layer, loadResources, resources, imgProps, i18n, className, children, ...etc } = this.props; const { ready, error, resource } = this.state; const cls = cx(classes.root, { [classes.ready]: ready }, className); return ( <Animation animate={animate} show={show} timeout={theme.animTime} {...animation} > {anim => ( <figure className={cx(cls, classes[anim.status])} {...etc}> <Frame animate={animate} show={show} layer={layer}> <div className={classes.holder}> <img {...imgProps} className={cx(classes.img, imgProps.className)} src={resource} /> {error && ( <div className={classes.error}>{i18n.error}</div> )} {!ready && !error && ( <Loading full animate={animate} show={show} layer={layer} /> )} </div> {!!children && ( <div className={classes.separator} /> )} {!!children && ( <figcaption className={classes.children}> <small> {typeof children === 'function' ? children(anim) : children} </small> </figcaption> )} </Frame> </figure> )} </Animation> ); } /** * If enabled, load the resources provided. * It doesn't return the state of the loading, it will update the state. */ loadResource () { const { resources, loadResources } = this.props; if (!loadResources) { return; } const responsive = this.responsive.get(); const resource = getResponsiveResource(resources, responsive); this.setState(this.getDefaultState()); this.loader .load({ images: [resource] }) .then(() => { this.setState({ ready: true, resource }); }, () => { this.setState({ error: true }); }); } }