import React, { SyntheticEvent } from 'react' import css from './Image.module.styl' interface Props { defaultHeight?: number src?: string sources?: Array deleteOnError?: boolean downgradeOnError?: string canFullscreen?: boolean max?: { height?: number|string width?: number|string } width?: number|string default?: { height?: number|string width?: number|string } alt?: string } const mimeTypes = { apng: 'image/apng', bmp: 'image/bmp', gif: 'image/gif', ico: 'image/x-icon', cur: 'image/x-icon', jpg: 'image/jpeg', jpeg: 'image/jpeg', jfif: 'image/jpeg', pjpeg: 'image/jpeg', pjp: 'image/jpeg', png: 'image/png', svg: 'image/svg+xml', tif: 'image/tiff', tiff: 'image/tiff', webp: 'image/webp', } const getMimeType = (img: string) => { const arr = img.split('.') return mimeTypes[arr[arr.length-1] as 'apng'] || mimeTypes.png } type evType = SyntheticEvent export default class Image extends React.Component { private ref: React.RefObject = React.createRef() private plchldr: React.RefObject = React.createRef() private parent: React.RefObject = React.createRef() private pic: React.RefObject = React.createRef() private wasDowngraded = false private cardPos: Array = [] private cardSize: Array = [] private isFullscreen = false public async componentDidMount() { if (this.props.canFullscreen) { window.addEventListener('scroll', this.onScroll) window.addEventListener('resize', this.onResize) this.onScroll() this.onResize() } } public async componentDidUpdate() { this.pic.current?.classList.remove(css.none) if (this.props.canFullscreen) { this.onScroll() this.onResize() } if (this.isFullscreen) {this.onClick()} } public async componentWillUnmount() { if (this.props.canFullscreen) { window.removeEventListener('scroll', this.onScroll) window.removeEventListener('resize', this.onResize) } } public render() { const pic = ( {this.props.sources && this.props.sources.map((el,index) => ( ))} {this.props.alt} ) if (this.props.canFullscreen) {return (
{pic}
)} return pic } private onScroll = async () => { if (!this.ref.current || this.isFullscreen || !this.props.canFullscreen) { return } this.cardPos = [this.ref.current.offsetTop - window.scrollY, this.ref.current.offsetLeft - window.scrollX] this.ref.current.style.top = this.cardPos[0] + 'px' this.ref.current.style.left = this.cardPos[1] + 'px' } private onResize = async () => { if (!this.ref.current || !this.plchldr.current || !this.props.canFullscreen || this.isFullscreen) { return } let tmp = [this.ref.current.offsetHeight, this.ref.current.offsetWidth] if (this.parent.current) { tmp = [this.parent.current.offsetHeight, this.ref.current.offsetWidth] } this.plchldr.current.style.width = `${tmp[1]}px` this.plchldr.current.style.height = `${tmp[0]}px` } private onClick = async () => { if (!this.ref.current || !this.props.canFullscreen || !this.plchldr.current) { return } const i = this.ref.current const c = this.plchldr.current const body = document.body i.style.top = this.cardPos[0] + 'px' i.style.left = this.cardPos[1] + 'px' if (this.isFullscreen) { i.style.width = this.cardSize[1] + 'px' i.style.height = this.cardSize[0] + 'px' body.classList.remove(css.hideOverflow) i.classList.remove(css.ph2) i.classList.add(css.after) setTimeout(() => { if (i.classList.contains(css.ph2) || i.classList.contains(css.ph1) || this.isFullscreen) {return} const w = this.valToPixel(this.props.width) const mh = this.valToPixel(this.props.max?.height) const mw = this.valToPixel(this.props.max?.width) c.classList.add(css.none) i.style.height = '' i.style.width = w i.style.maxHeight = mh i.style.maxWidth = mw i.classList.remove(css.after) }, 350) this.isFullscreen = false } else { i.classList.add(css.ph1) c.classList.remove(css.none) i.classList.add(css.ph2) i.classList.remove(css.ph1) body.classList.add(css.hideOverflow) this.isFullscreen = true } } private valToPixel(value: number|string|undefined): string { if (typeof value === 'number') { return `${value}px` } if (typeof value === 'undefined') { return '' } return value } private onLoad = async (ev: evType) => { ev.currentTarget.style.height = '' ev.currentTarget.style.width = '' } private onError = async (ev: evType) => { this.w('Picture not loaded', ev.currentTarget.src) ev.currentTarget.parentElement?.classList.add(css.none) } private w(...messages: any) { console.warn('[ Picture ]', ...messages) } }