UNPKG

@nichoth/image

Version:
101 lines (88 loc) 3.42 kB
// @ts-check import { Cloudinary } from '@cloudinary/url-gen' import { scale } from '@cloudinary/url-gen/actions/resize' import Tonic from '@nichoth/tonic' import { CloudinarySrcset } from './srcset.js' /** * This is a factory function that returns an object like { Image }, * where `Image` is a preact component * @param config {{ cloudName:string }} The cloudName for Cloudinary * @returns { { BlurredImage, ImageTag } } Tonic components */ export const CloudinaryTonic = function ({ cloudName }) { const cld = new Cloudinary({ cloud: { cloudName }, url: { secure: true } }) /** * A `tonic` component for images. * Be sure to pass an `id` in HTML to the component. Also takes a prop * `blurPlaceholder`, which is a base64 string to use inline as src, * and a prop `filename` -- the filename to fetch * @returns {HTMLElement} HTML element created with `tonic` */ class BlurredImage extends Tonic { constructor () { super() const imgLarge = new window.Image() imgLarge.classList.add('sharp') this.state = { blurry: true, imgLarge } imgLarge.onload = async () => { this.state.blurry = false await this.reRender() const placeholder = this.querySelector('.placeholder') imgLarge.classList.add('loaded') if (placeholder) placeholder.appendChild(imgLarge) } } getImg () { const { filename, maxwidth, sizes } = this.props const { imgLarge } = this.state const { defaultSrcset } = CloudinarySrcset(cld) const srcset = defaultSrcset(filename) imgLarge.setAttribute('srcset', srcset) imgLarge.setAttribute('sizes', sizes) imgLarge.src = (cld.image(filename) .format('auto') .quality('auto') .resize(scale().width(maxwidth)) .toURL()) } render () { const { blurplaceholder, className } = this.props const _class = (this.props.class || className) if (this.state.blurry) { this.getImg() } return this.html`<div class=${('placeholder' + (_class ? ` ${_class}` : ''))} > <img class="blurry" src=${blurplaceholder} /> </div>` } } class ImageTag extends Tonic { render () { const { sizes, className, filename, decoding, loading, fetchpriority } = this.props const _class = (this.props.class || className) const { defaultSrcset } = CloudinarySrcset(cld) const src = (cld.image(filename) .format('auto') .quality('auto') .toURL()) const srcset = defaultSrcset(filename) return this.html`<div class=${'image' + (_class ? ` ${_class}` : '')}> <img srcset="${srcset}" sizes="${sizes}" src=${src} decoding="${decoding || 'auto'}" loading="${loading || 'lazy'}" fetchpriority="${fetchpriority || 'low'}" /> </div>` } } return { BlurredImage, ImageTag } }